@goscribe/server 1.1.2 → 1.1.4

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 (36) hide show
  1. package/dist/lib/ai-session.d.ts +13 -3
  2. package/dist/lib/ai-session.js +66 -146
  3. package/dist/lib/pusher.js +1 -1
  4. package/dist/routers/_app.d.ts +114 -7
  5. package/dist/routers/chat.js +2 -23
  6. package/dist/routers/flashcards.d.ts +25 -1
  7. package/dist/routers/flashcards.js +0 -14
  8. package/dist/routers/members.d.ts +18 -0
  9. package/dist/routers/members.js +14 -1
  10. package/dist/routers/worksheets.js +5 -4
  11. package/dist/routers/workspace.d.ts +89 -6
  12. package/dist/routers/workspace.js +389 -259
  13. package/dist/services/flashcard-progress.service.d.ts +25 -1
  14. package/dist/services/flashcard-progress.service.js +70 -31
  15. package/package.json +3 -2
  16. package/prisma/schema.prisma +196 -184
  17. package/src/lib/ai-session.ts +3 -21
  18. package/src/routers/auth.ts +50 -2
  19. package/src/routers/flashcards.ts +0 -16
  20. package/src/routers/members.ts +27 -6
  21. package/src/routers/workspace.ts +468 -439
  22. package/src/server.ts +13 -0
  23. package/ANALYSIS_PROGRESS_SPEC.md +0 -463
  24. package/PROGRESS_QUICK_REFERENCE.md +0 -239
  25. package/dist/lib/podcast-prompts.d.ts +0 -43
  26. package/dist/lib/podcast-prompts.js +0 -135
  27. package/dist/routers/ai-session.d.ts +0 -0
  28. package/dist/routers/ai-session.js +0 -1
  29. package/dist/services/flashcard.service.d.ts +0 -183
  30. package/dist/services/flashcard.service.js +0 -224
  31. package/dist/services/podcast-segment-reorder.d.ts +0 -0
  32. package/dist/services/podcast-segment-reorder.js +0 -107
  33. package/dist/services/podcast.service.d.ts +0 -0
  34. package/dist/services/podcast.service.js +0 -326
  35. package/dist/services/worksheet.service.d.ts +0 -0
  36. package/dist/services/worksheet.service.js +0 -295
@@ -1,11 +1,10 @@
1
-
2
1
  generator client {
3
2
  provider = "prisma-client-js"
4
3
  }
5
4
 
6
5
  datasource db {
7
- provider = "postgresql"
8
- url = env("DATABASE_URL")
6
+ provider = "postgresql"
7
+ url = env("DATABASE_URL")
9
8
  directUrl = env("DIRECT_URL") // for shadow db in migrations
10
9
  }
11
10
 
@@ -39,39 +38,51 @@ enum QuestionType {
39
38
  // NextAuth-compatible auth models (minimal)
40
39
  //
41
40
  model User {
42
- id String @id @default(cuid())
43
- name String?
44
- email String? @unique
45
- emailVerified DateTime?
46
- passwordHash String? // for credentials login
47
- image String?
48
- session Session[]
41
+ id String @id @default(cuid())
42
+ name String?
43
+ email String? @unique
44
+ emailVerified DateTime?
45
+ passwordHash String? // for credentials login
46
+ profilePicture FileAsset? @relation(fields: [fileAssetId], references: [id])
47
+ session Session[]
49
48
 
50
49
  // Ownership
51
- folders Folder[] @relation("UserFolders")
52
- workspaces Workspace[] @relation("UserWorkspaces")
53
- invitedInWorkspaces Workspace[] @relation("WorkspaceSharedWith") // many-to-many (deprecated)
50
+ folders Folder[] @relation("UserFolders")
51
+ workspaces Workspace[] @relation("UserWorkspaces")
52
+ invitedInWorkspaces Workspace[] @relation("WorkspaceSharedWith") // many-to-many (deprecated)
54
53
  workspaceMemberships WorkspaceMember[] // proper member management
55
- uploads FileAsset[] @relation("UserUploads")
56
- artifacts Artifact[] @relation("UserArtifacts")
57
- versions ArtifactVersion[] @relation("UserArtifactVersions")
58
-
54
+ uploads FileAsset[] @relation("UserUploads")
55
+ artifacts Artifact[] @relation("UserArtifacts")
56
+ versions ArtifactVersion[] @relation("UserArtifactVersions")
57
+
59
58
  // Progress tracking
60
- flashcardProgress FlashcardProgress[] @relation("UserFlashcardProgress")
59
+ flashcardProgress FlashcardProgress[] @relation("UserFlashcardProgress")
61
60
  worksheetQuestionProgress WorksheetQuestionProgress[]
62
-
61
+
63
62
  // Invitations
64
63
  sentInvitations WorkspaceInvitation[] @relation("UserInvitations")
65
64
 
65
+ notifications Notification[]
66
66
  chats Chat[]
67
- createdAt DateTime @default(now())
68
- updatedAt DateTime @updatedAt
67
+ createdAt DateTime @default(now())
68
+ updatedAt DateTime @updatedAt
69
+ fileAssetId String?
70
+ }
71
+
72
+ model Notification {
73
+ id String @id @default(cuid())
74
+ userId String
75
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
76
+ content String
77
+ read Boolean @default(false)
78
+ createdAt DateTime @default(now())
79
+ updatedAt DateTime @updatedAt
69
80
  }
70
81
 
71
82
  model Session {
72
- id String @id @default(cuid())
73
- userId String
74
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
83
+ id String @id @default(cuid())
84
+ userId String
85
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
75
86
  expires DateTime
76
87
  }
77
88
 
@@ -87,62 +98,62 @@ model VerificationToken {
87
98
  // Filesystem-like structure
88
99
  //
89
100
  model Folder {
90
- id String @id @default(cuid())
91
- name String
92
- ownerId String
93
- owner User @relation("UserFolders", fields: [ownerId], references: [id], onDelete: Cascade)
101
+ id String @id @default(cuid())
102
+ name String
103
+ ownerId String
104
+ owner User @relation("UserFolders", fields: [ownerId], references: [id], onDelete: Cascade)
94
105
 
95
106
  // Nested folders
96
- parentId String?
97
- parent Folder? @relation("FolderChildren", fields: [parentId], references: [id], onDelete: Cascade)
98
- children Folder[] @relation("FolderChildren")
99
- color String @default("#9D00FF")
107
+ parentId String?
108
+ parent Folder? @relation("FolderChildren", fields: [parentId], references: [id], onDelete: Cascade)
109
+ children Folder[] @relation("FolderChildren")
110
+ color String @default("#9D00FF")
100
111
 
101
112
  // Files (workspaces) inside folders
102
113
  workspaces Workspace[]
103
114
 
104
115
  // Metadata
105
- createdAt DateTime @default(now())
106
- updatedAt DateTime @updatedAt
116
+ createdAt DateTime @default(now())
117
+ updatedAt DateTime @updatedAt
107
118
 
108
119
  // Helpful composite index: folders per owner + parent
109
120
  @@index([ownerId, parentId])
110
121
  }
111
122
 
112
123
  model Workspace {
113
- id String @id @default(cuid())
124
+ id String @id @default(cuid())
114
125
  title String
115
- description String? // optional notes/description for the "file"
126
+ description String? // optional notes/description for the "file"
116
127
  ownerId String
117
- owner User @relation("UserWorkspaces", fields: [ownerId], references: [id], onDelete: Cascade)
118
- icon String @default("📄")
119
- color String @default("#9D00FF")
128
+ owner User @relation("UserWorkspaces", fields: [ownerId], references: [id], onDelete: Cascade)
129
+ icon String @default("📄")
130
+ color String @default("#9D00FF")
120
131
 
121
132
  // A workspace (file) lives in a folder (nullable = root)
122
- folderId String?
123
- folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull)
124
-
125
- channels Channel[]
133
+ folderId String?
134
+ folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull)
126
135
 
127
- sharedWith User[] @relation("WorkspaceSharedWith") // many-to-many for sharing (deprecated)
128
- members WorkspaceMember[] // proper member management with roles
129
- fileBeingAnalyzed Boolean @default(false)
136
+ channels Channel[]
137
+
138
+ sharedWith User[] @relation("WorkspaceSharedWith") // many-to-many for sharing (deprecated)
139
+ members WorkspaceMember[] // proper member management with roles
140
+ fileBeingAnalyzed Boolean @default(false)
130
141
 
131
142
  analysisProgress Json?
132
143
 
133
144
  needsAnalysis Boolean @default(false)
134
145
 
135
146
  // Raw uploads attached to this workspace
136
- uploads FileAsset[]
147
+ uploads FileAsset[]
137
148
 
138
149
  // AI outputs for this workspace (study guides, flashcards, etc.)
139
- artifacts Artifact[]
140
-
150
+ artifacts Artifact[]
151
+
141
152
  // Invitations
142
153
  invitations WorkspaceInvitation[]
143
154
 
144
- createdAt DateTime @default(now())
145
- updatedAt DateTime @updatedAt
155
+ createdAt DateTime @default(now())
156
+ updatedAt DateTime @updatedAt
146
157
 
147
158
  @@index([ownerId, folderId])
148
159
  }
@@ -152,25 +163,25 @@ model Channel {
152
163
  workspaceId String
153
164
  workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
154
165
 
155
- name String
166
+ name String
156
167
 
157
- createdAt DateTime @default(now())
158
- chats Chat[]
168
+ createdAt DateTime @default(now())
169
+ chats Chat[]
159
170
 
160
171
  @@index([workspaceId])
161
172
  }
162
173
 
163
174
  model Chat {
164
- id String @id @default(cuid())
165
- channelId String
166
- channel Channel @relation(fields: [channelId], references: [id], onDelete: Cascade)
175
+ id String @id @default(cuid())
176
+ channelId String
177
+ channel Channel @relation(fields: [channelId], references: [id], onDelete: Cascade)
167
178
 
168
- user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
169
- userId String?
170
- message String // chat message content
179
+ user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
180
+ userId String?
181
+ message String // chat message content
171
182
 
172
- updatedAt DateTime @updatedAt
173
- createdAt DateTime @default(now())
183
+ updatedAt DateTime @updatedAt
184
+ createdAt DateTime @default(now())
174
185
 
175
186
  @@index([channelId, createdAt])
176
187
  }
@@ -179,25 +190,26 @@ model Chat {
179
190
  // User uploads (source materials for AI)
180
191
  //
181
192
  model FileAsset {
182
- id String @id @default(cuid())
183
- workspaceId String
184
- workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
193
+ id String @id @default(cuid())
194
+ workspaceId String?
195
+ workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
185
196
 
186
- userId String
187
- user User @relation("UserUploads", fields: [userId], references: [id], onDelete: Cascade)
197
+ userId String?
198
+ user User? @relation("UserUploads", fields: [userId], references: [id], onDelete: Cascade)
188
199
 
189
- name String
190
- mimeType String
191
- size Int
192
- bucket String?
193
- objectKey String?
194
- url String? // optional if serving via signed GET per-view
195
- checksum String? // optional server-side integrity
196
- aiTranscription String?
200
+ name String
201
+ mimeType String
202
+ size Int
203
+ bucket String?
204
+ objectKey String?
205
+ url String? // optional if serving via signed GET per-view
206
+ checksum String? // optional server-side integrity
207
+ aiTranscription Json? @default("{}")
197
208
 
198
- meta Json? // arbitrary metadata
209
+ meta Json? // arbitrary metadata
199
210
 
200
211
  createdAt DateTime @default(now())
212
+ User User[]
201
213
 
202
214
  @@index([workspaceId])
203
215
  @@index([userId, createdAt])
@@ -209,56 +221,56 @@ model FileAsset {
209
221
  // - Some artifact types (flashcards, worksheet) have child rows
210
222
  //
211
223
  model Artifact {
212
- id String @id @default(cuid())
224
+ id String @id @default(cuid())
213
225
  workspaceId String
214
- workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
226
+ workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
215
227
 
216
- type ArtifactType
217
- title String
218
- isArchived Boolean @default(false)
228
+ type ArtifactType
229
+ title String
230
+ isArchived Boolean @default(false)
219
231
 
220
- generating Boolean @default(false)
221
- generatingMetadata Json?
232
+ generating Boolean @default(false)
233
+ generatingMetadata Json?
222
234
 
223
235
  // Worksheet-specific fields
224
- difficulty Difficulty? // only meaningful for WORKSHEET
225
- estimatedTime String? // only meaningful for WORKSHEET
236
+ difficulty Difficulty? // only meaningful for WORKSHEET
237
+ estimatedTime String? // only meaningful for WORKSHEET
226
238
 
227
239
  imageObjectKey String?
228
- description String?
240
+ description String?
229
241
 
230
242
  createdById String?
231
- createdBy User? @relation("UserArtifacts", fields: [createdById], references: [id], onDelete: SetNull)
243
+ createdBy User? @relation("UserArtifacts", fields: [createdById], references: [id], onDelete: SetNull)
232
244
 
233
- versions ArtifactVersion[] // text/transcript versions etc.
234
- flashcards Flashcard[] // only meaningful for FLASHCARD_SET
235
- questions WorksheetQuestion[] // only meaningful for WORKSHEET
245
+ versions ArtifactVersion[] // text/transcript versions etc.
246
+ flashcards Flashcard[] // only meaningful for FLASHCARD_SET
247
+ questions WorksheetQuestion[] // only meaningful for WORKSHEET
236
248
  podcastSegments PodcastSegment[] // only meaningful for PODCAST_EPISODE
237
249
 
238
- createdAt DateTime @default(now())
239
- updatedAt DateTime @updatedAt
250
+ createdAt DateTime @default(now())
251
+ updatedAt DateTime @updatedAt
240
252
 
241
253
  @@index([workspaceId, type])
242
254
  }
243
255
 
244
256
  model ArtifactVersion {
245
- id String @id @default(cuid())
246
- artifactId String
247
- artifact Artifact @relation(fields: [artifactId], references: [id], onDelete: Cascade)
257
+ id String @id @default(cuid())
258
+ artifactId String
259
+ artifact Artifact @relation(fields: [artifactId], references: [id], onDelete: Cascade)
248
260
 
249
261
  // Plain text content (e.g., Study Guide body, Meeting Summary text, Podcast transcript)
250
- content String // rich text serialized as markdown/HTML stored as TEXT
262
+ content String // rich text serialized as markdown/HTML stored as TEXT
251
263
 
252
264
  // For Podcast episodes or other media, store URLs / durations / etc. in data
253
- data Json? // e.g., { "audioUrl": "...", "durationSec": 312, "voice": "..." }
265
+ data Json? // e.g., { "audioUrl": "...", "durationSec": 312, "voice": "..." }
254
266
 
255
267
  // Version sequencing (auto-increment per artifact)
256
- version Int
268
+ version Int
257
269
 
258
270
  createdById String?
259
- createdBy User? @relation("UserArtifactVersions", fields: [createdById], references: [id], onDelete: SetNull)
271
+ createdBy User? @relation("UserArtifactVersions", fields: [createdById], references: [id], onDelete: SetNull)
260
272
 
261
- createdAt DateTime @default(now())
273
+ createdAt DateTime @default(now())
262
274
 
263
275
  @@unique([artifactId, version]) // each artifact has 1,2,3...
264
276
  @@index([artifactId])
@@ -272,15 +284,15 @@ model Flashcard {
272
284
  artifactId String
273
285
  artifact Artifact @relation(fields: [artifactId], references: [id], onDelete: Cascade)
274
286
 
275
- front String // question/term
276
- back String // answer/definition
277
- tags String[] // optional keywords
278
- order Int @default(0)
287
+ front String // question/term
288
+ back String // answer/definition
289
+ tags String[] // optional keywords
290
+ order Int @default(0)
279
291
 
280
292
  // User progress tracking
281
- progress FlashcardProgress[]
293
+ progress FlashcardProgress[]
282
294
 
283
- createdAt DateTime @default(now())
295
+ createdAt DateTime @default(now())
284
296
 
285
297
  @@index([artifactId])
286
298
  }
@@ -289,33 +301,33 @@ model Flashcard {
289
301
  // User Progress on Flashcards (spaced repetition, mastery tracking)
290
302
  //
291
303
  model FlashcardProgress {
292
- id String @id @default(cuid())
293
- userId String
294
- user User @relation("UserFlashcardProgress", fields: [userId], references: [id], onDelete: Cascade)
295
-
304
+ id String @id @default(cuid())
305
+ userId String
306
+ user User @relation("UserFlashcardProgress", fields: [userId], references: [id], onDelete: Cascade)
307
+
296
308
  flashcardId String
297
309
  flashcard Flashcard @relation(fields: [flashcardId], references: [id], onDelete: Cascade)
298
310
 
299
311
  // Study statistics
300
- timesStudied Int @default(0)
301
- timesCorrect Int @default(0)
302
- timesIncorrect Int @default(0)
303
- timesIncorrectConsecutive Int @default(0) // Track consecutive failures
304
-
312
+ timesStudied Int @default(0)
313
+ timesCorrect Int @default(0)
314
+ timesIncorrect Int @default(0)
315
+ timesIncorrectConsecutive Int @default(0) // Track consecutive failures
316
+
305
317
  // Spaced repetition data
306
- easeFactor Float @default(2.5) // SM-2 algorithm ease factor
307
- interval Int @default(0) // Days until next review
308
- repetitions Int @default(0) // Consecutive correct answers
309
-
318
+ easeFactor Float @default(2.5) // SM-2 algorithm ease factor
319
+ interval Int @default(0) // Days until next review
320
+ repetitions Int @default(0) // Consecutive correct answers
321
+
310
322
  // Mastery level (0-100)
311
- masteryLevel Int @default(0)
312
-
323
+ masteryLevel Int @default(0)
324
+
313
325
  // Timestamps
314
- lastStudiedAt DateTime?
315
- nextReviewAt DateTime?
316
-
317
- createdAt DateTime @default(now())
318
- updatedAt DateTime @updatedAt
326
+ lastStudiedAt DateTime?
327
+ nextReviewAt DateTime?
328
+
329
+ createdAt DateTime @default(now())
330
+ updatedAt DateTime @updatedAt
319
331
 
320
332
  @@unique([userId, flashcardId])
321
333
  @@index([userId, nextReviewAt])
@@ -326,9 +338,9 @@ model FlashcardProgress {
326
338
  // Worksheet Questions (child items of a WORKSHEET Artifact)
327
339
  //
328
340
  model WorksheetQuestion {
329
- id String @id @default(cuid())
341
+ id String @id @default(cuid())
330
342
  artifactId String
331
- artifact Artifact @relation(fields: [artifactId], references: [id], onDelete: Cascade)
343
+ artifact Artifact @relation(fields: [artifactId], references: [id], onDelete: Cascade)
332
344
 
333
345
  prompt String
334
346
  answer String?
@@ -336,35 +348,35 @@ model WorksheetQuestion {
336
348
  difficulty Difficulty @default(MEDIUM)
337
349
  order Int @default(0)
338
350
 
339
- meta Json? // e.g., { "choices": ["A","B","C","D"], "correct": 1, "options": [...] }
351
+ meta Json? // e.g., { "choices": ["A","B","C","D"], "correct": 1, "options": [...] }
340
352
 
341
- createdAt DateTime @default(now())
353
+ createdAt DateTime @default(now())
354
+ progress WorksheetQuestionProgress[]
342
355
 
343
356
  @@index([artifactId])
344
- progress WorksheetQuestionProgress[]
345
357
  }
346
358
 
347
359
  //
348
360
  // Per-user progress for Worksheet Questions
349
361
  //
350
362
  model WorksheetQuestionProgress {
351
- id String @id @default(cuid())
352
- worksheetQuestionId String
353
- worksheetQuestion WorksheetQuestion @relation(fields: [worksheetQuestionId], references: [id], onDelete: Cascade)
363
+ id String @id @default(cuid())
364
+ worksheetQuestionId String
365
+ worksheetQuestion WorksheetQuestion @relation(fields: [worksheetQuestionId], references: [id], onDelete: Cascade)
354
366
 
355
- userId String
356
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
367
+ userId String
368
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
357
369
 
358
- modified Boolean @default(false)
359
- userAnswer String?
360
- correct Boolean? @default(false)
361
- completedAt DateTime?
362
- attempts Int @default(0)
363
- timeSpentSec Int?
364
- meta Json?
370
+ modified Boolean @default(false)
371
+ userAnswer String?
372
+ correct Boolean? @default(false)
373
+ completedAt DateTime?
374
+ attempts Int @default(0)
375
+ timeSpentSec Int?
376
+ meta Json?
365
377
 
366
- createdAt DateTime @default(now())
367
- updatedAt DateTime @updatedAt
378
+ createdAt DateTime @default(now())
379
+ updatedAt DateTime @updatedAt
368
380
 
369
381
  @@unique([worksheetQuestionId, userId])
370
382
  @@index([userId])
@@ -377,15 +389,15 @@ model WorkspaceMember {
377
389
  id String @id @default(cuid())
378
390
  workspaceId String
379
391
  workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
380
-
381
- userId String
382
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
383
-
384
- role String @default("member") // "owner", "admin", "member"
385
-
386
- joinedAt DateTime @default(now())
387
- updatedAt DateTime @updatedAt
388
-
392
+
393
+ userId String
394
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
395
+
396
+ role String @default("member") // "owner", "admin", "member"
397
+
398
+ joinedAt DateTime @default(now())
399
+ updatedAt DateTime @updatedAt
400
+
389
401
  @@unique([workspaceId, userId]) // One membership per user per workspace
390
402
  @@index([workspaceId])
391
403
  @@index([userId])
@@ -398,20 +410,20 @@ model WorkspaceInvitation {
398
410
  id String @id @default(cuid())
399
411
  workspaceId String
400
412
  workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
401
-
402
- email String
403
- role String @default("member") // "owner", "admin", "member"
404
- token String @unique @default(cuid()) // UUID for invitation link
405
-
413
+
414
+ email String
415
+ role String @default("member") // "owner", "admin", "member"
416
+ token String @unique @default(cuid()) // UUID for invitation link
417
+
406
418
  invitedById String
407
- invitedBy User @relation("UserInvitations", fields: [invitedById], references: [id], onDelete: Cascade)
408
-
409
- acceptedAt DateTime?
410
- expiresAt DateTime @default(dbgenerated("NOW() + INTERVAL '7 days'"))
411
-
412
- createdAt DateTime @default(now())
413
- updatedAt DateTime @updatedAt
414
-
419
+ invitedBy User @relation("UserInvitations", fields: [invitedById], references: [id], onDelete: Cascade)
420
+
421
+ acceptedAt DateTime?
422
+ expiresAt DateTime @default(dbgenerated("NOW() + INTERVAL '7 days'"))
423
+
424
+ createdAt DateTime @default(now())
425
+ updatedAt DateTime @updatedAt
426
+
415
427
  @@unique([workspaceId, email]) // One invitation per email per workspace
416
428
  @@index([token])
417
429
  @@index([workspaceId])
@@ -425,26 +437,26 @@ model PodcastSegment {
425
437
  artifactId String
426
438
  artifact Artifact @relation(fields: [artifactId], references: [id], onDelete: Cascade)
427
439
 
428
- title String
429
- content String // Full text content of the segment
430
- startTime Int // Start time in seconds
431
- duration Int // Duration in seconds
432
- order Int // Display order within the episode
433
-
440
+ title String
441
+ content String // Full text content of the segment
442
+ startTime Int // Start time in seconds
443
+ duration Int // Duration in seconds
444
+ order Int // Display order within the episode
445
+
434
446
  // Audio file reference
435
- objectKey String? // Google Cloud Storage object key
436
- audioUrl String? // Cached signed URL (temporary)
437
-
447
+ objectKey String? // Google Cloud Storage object key
448
+ audioUrl String? // Cached signed URL (temporary)
449
+
438
450
  // Metadata
439
- keyPoints String[] // Array of key points
440
- meta Json? // Additional metadata (voice settings, etc.)
441
-
442
- generating Boolean @default(false)
451
+ keyPoints String[] // Array of key points
452
+ meta Json? // Additional metadata (voice settings, etc.)
453
+
454
+ generating Boolean @default(false)
443
455
  generatingMetadata Json? // Additional metadata (voice settings, etc.)
444
-
445
- createdAt DateTime @default(now())
446
- updatedAt DateTime @updatedAt
456
+
457
+ createdAt DateTime @default(now())
458
+ updatedAt DateTime @updatedAt
447
459
 
448
460
  @@index([artifactId, order]) // For efficient ordering
449
461
  @@index([artifactId, startTime]) // For time-based queries
450
- }
462
+ }
@@ -136,11 +136,6 @@ export class AISessionService {
136
136
  fileType: 'image' | 'pdf',
137
137
  maxPages?: number
138
138
  ): Promise<ProcessFileResult> {
139
- const session = this.sessions.get(sessionId);
140
- if (!session) {
141
- throw new TRPCError({ code: 'NOT_FOUND', message: 'AI session not found' });
142
- }
143
-
144
139
  await new Promise(resolve => setTimeout(resolve, IMITATE_WAIT_TIME_MS));
145
140
 
146
141
  // Mock mode - return fake processing result
@@ -168,6 +163,8 @@ export class AISessionService {
168
163
  formData.append('maxPages', maxPages.toString());
169
164
  }
170
165
 
166
+ console.log('formData', formData);
167
+
171
168
  // Retry logic for file processing
172
169
  const maxRetries = 3;
173
170
  let lastError: Error | null = null;
@@ -183,7 +180,7 @@ export class AISessionService {
183
180
  const response = await fetch(AI_SERVICE_URL, {
184
181
  method: 'POST',
185
182
  body: formData,
186
- signal: controller.signal,
183
+ // signal: controller.signal,
187
184
  });
188
185
 
189
186
  clearTimeout(timeoutId);
@@ -201,11 +198,6 @@ export class AISessionService {
201
198
  throw new Error(result.error || 'File processing failed');
202
199
  }
203
200
 
204
- // Update session
205
- session.files.push(fileUrl);
206
- session.updatedAt = new Date();
207
- this.sessions.set(sessionId, session);
208
-
209
201
  return result as ProcessFileResult;
210
202
 
211
203
  } catch (error) {
@@ -235,11 +227,6 @@ export class AISessionService {
235
227
 
236
228
  // Generate study guide
237
229
  async generateStudyGuide(sessionId: string, user: string): Promise<string> {
238
- const session = this.sessions.get(sessionId);
239
- if (!session) {
240
- throw new TRPCError({ code: 'NOT_FOUND', message: 'AI session not found' });
241
- }
242
-
243
230
  await new Promise(resolve => setTimeout(resolve, IMITATE_WAIT_TIME_MS));
244
231
  // Mock mode - return fake study guide
245
232
  if (MOCK_MODE) {
@@ -291,11 +278,6 @@ This mock study guide demonstrates the structure and format that would be genera
291
278
 
292
279
  // Generate flashcard questions
293
280
  async generateFlashcardQuestions(sessionId: string, user: string, numQuestions: number, difficulty: 'easy' | 'medium' | 'hard'): Promise<string> {
294
- // const session = this.sessions.get(sessionId);
295
- // if (!session) {
296
- // throw new TRPCError({ code: 'NOT_FOUND', message: 'AI session not found' });
297
- // }
298
-
299
281
  await new Promise(resolve => setTimeout(resolve, IMITATE_WAIT_TIME_MS));
300
282
  // Mock mode - return fake flashcard questions
301
283
  if (MOCK_MODE) {