@goscribe/server 1.3.4 → 1.6.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 (383) hide show
  1. package/.env.example +12 -0
  2. package/.vscode/settings.json +3 -0
  3. package/REFACTOR_NOTES.md +60 -0
  4. package/TESTING_PROMPT.md +225 -0
  5. package/dist/context.d.ts +14 -1
  6. package/dist/context.js +23 -2
  7. package/dist/controllers/admin.controller.d.ts +715 -0
  8. package/dist/controllers/admin.controller.js +9 -0
  9. package/dist/controllers/annotations.controller.d.ts +439 -0
  10. package/dist/controllers/annotations.controller.js +9 -0
  11. package/dist/controllers/app-router.controller.d.ts +3011 -0
  12. package/dist/controllers/app-router.controller.js +38 -0
  13. package/dist/controllers/app-router.controller.test.d.ts +1 -0
  14. package/dist/controllers/app-router.controller.test.js +36 -0
  15. package/dist/controllers/auth.controller.d.ts +323 -0
  16. package/dist/controllers/auth.controller.js +9 -0
  17. package/dist/controllers/base.controller.d.ts +4 -0
  18. package/dist/controllers/base.controller.js +5 -0
  19. package/dist/controllers/chat.controller.d.ts +341 -0
  20. package/dist/controllers/chat.controller.js +9 -0
  21. package/dist/controllers/copilot.controller.d.ts +397 -0
  22. package/dist/controllers/copilot.controller.js +9 -0
  23. package/dist/controllers/flashcards.controller.d.ts +651 -0
  24. package/dist/controllers/flashcards.controller.js +9 -0
  25. package/dist/controllers/members.controller.d.ts +339 -0
  26. package/dist/controllers/members.controller.js +9 -0
  27. package/dist/controllers/notifications.controller.d.ts +199 -0
  28. package/dist/controllers/notifications.controller.js +9 -0
  29. package/dist/controllers/payment.controller.d.ts +181 -0
  30. package/dist/controllers/payment.controller.js +9 -0
  31. package/dist/controllers/podcast.controller.d.ts +575 -0
  32. package/dist/controllers/podcast.controller.js +9 -0
  33. package/dist/controllers/router-module.controller.d.ts +5 -0
  34. package/dist/controllers/router-module.controller.js +6 -0
  35. package/dist/controllers/studyguide.controller.d.ts +73 -0
  36. package/dist/controllers/studyguide.controller.js +9 -0
  37. package/dist/controllers/worksheets.controller.d.ts +829 -0
  38. package/dist/controllers/worksheets.controller.js +9 -0
  39. package/dist/controllers/workspace.controller.d.ts +1207 -0
  40. package/dist/controllers/workspace.controller.js +9 -0
  41. package/dist/lib/activity_human_description.test.js +16 -15
  42. package/dist/lib/activity_log_service.test.js +28 -23
  43. package/dist/lib/ai/config.d.ts +20 -0
  44. package/dist/lib/ai/config.js +31 -0
  45. package/dist/lib/ai/embedding-client.d.ts +8 -0
  46. package/dist/lib/ai/embedding-client.js +30 -0
  47. package/dist/lib/ai/index.d.ts +48 -0
  48. package/dist/lib/ai/index.js +29 -0
  49. package/dist/lib/ai/inference-backend/client.d.ts +28 -0
  50. package/dist/lib/ai/inference-backend/client.js +301 -0
  51. package/dist/lib/ai/inference-backend/mocks.d.ts +12 -0
  52. package/dist/lib/ai/inference-backend/mocks.js +133 -0
  53. package/dist/lib/ai/inference-backend/types.d.ts +44 -0
  54. package/dist/lib/ai/inference-backend/types.js +1 -0
  55. package/dist/lib/ai/json-parse.d.ts +2 -0
  56. package/dist/lib/ai/json-parse.js +34 -0
  57. package/dist/lib/ai/llm-client.d.ts +7 -0
  58. package/dist/lib/ai/llm-client.js +36 -0
  59. package/dist/lib/ai/mock.d.ts +2 -0
  60. package/dist/lib/ai/mock.js +10 -0
  61. package/dist/lib/ai/types.d.ts +9 -0
  62. package/dist/lib/ai/types.js +1 -0
  63. package/dist/lib/chunking.d.ts +19 -0
  64. package/dist/lib/chunking.js +47 -0
  65. package/dist/lib/curated-kb-seed.d.ts +12 -0
  66. package/dist/lib/curated-kb-seed.js +155 -0
  67. package/dist/lib/email.js +67 -108
  68. package/dist/lib/embeddings.d.ts +2 -0
  69. package/dist/lib/embeddings.js +1 -0
  70. package/dist/lib/ensure-curated-kb-catalog.d.ts +6 -0
  71. package/dist/lib/ensure-curated-kb-catalog.js +53 -0
  72. package/dist/lib/env.d.ts +1 -5
  73. package/dist/lib/env.js +2 -7
  74. package/dist/lib/inference.d.ts +1 -8
  75. package/dist/lib/inference.js +1 -19
  76. package/dist/lib/kb-meta.d.ts +8 -0
  77. package/dist/lib/kb-meta.js +77 -0
  78. package/dist/lib/note-text.d.ts +1 -0
  79. package/dist/lib/note-text.js +47 -0
  80. package/dist/lib/notification-service.test.js +37 -36
  81. package/dist/lib/pdf.d.ts +11 -0
  82. package/dist/lib/pdf.js +11 -0
  83. package/dist/lib/usage_service.d.ts +2 -1
  84. package/dist/lib/usage_service.js +30 -12
  85. package/dist/lib/worksheet-generation.js +4 -4
  86. package/dist/lib/worksheet-generation.test.js +32 -17
  87. package/dist/lib/workspace-kb.d.ts +5 -0
  88. package/dist/lib/workspace-kb.js +7 -0
  89. package/dist/models/controller-context.model.d.ts +8 -0
  90. package/dist/models/controller-context.model.js +1 -0
  91. package/dist/repositories/artifact.repository.d.ts +60 -0
  92. package/dist/repositories/artifact.repository.js +40 -0
  93. package/dist/repositories/base.repository.d.ts +14 -0
  94. package/dist/repositories/base.repository.js +14 -0
  95. package/dist/repositories/invitation.repository.d.ts +94 -0
  96. package/dist/repositories/invitation.repository.js +44 -0
  97. package/dist/repositories/notification.repository.d.ts +72 -0
  98. package/dist/repositories/notification.repository.js +44 -0
  99. package/dist/repositories/router-module.repository.d.ts +10 -0
  100. package/dist/repositories/router-module.repository.js +14 -0
  101. package/dist/repositories/user.repository.d.ts +74 -0
  102. package/dist/repositories/user.repository.js +37 -0
  103. package/dist/repositories/workspace-member.repository.d.ts +31 -0
  104. package/dist/repositories/workspace-member.repository.js +31 -0
  105. package/dist/repositories/workspace.repository.d.ts +97 -0
  106. package/dist/repositories/workspace.repository.js +79 -0
  107. package/dist/routers/_app.d.ts +566 -111
  108. package/dist/routers/_app.js +4 -0
  109. package/dist/routers/admin.d.ts +0 -4
  110. package/dist/routers/admin.js +21 -549
  111. package/dist/routers/annotations.js +12 -170
  112. package/dist/routers/artifactVersions.d.ts +65 -0
  113. package/dist/routers/artifactVersions.js +14 -0
  114. package/dist/routers/auth.d.ts +0 -6
  115. package/dist/routers/auth.js +37 -422
  116. package/dist/routers/chat.js +15 -229
  117. package/dist/routers/copilot.d.ts +14 -13
  118. package/dist/routers/copilot.js +13 -532
  119. package/dist/routers/flashcards.d.ts +17 -6
  120. package/dist/routers/flashcards.js +23 -349
  121. package/dist/routers/knowledgeBase.d.ts +421 -0
  122. package/dist/routers/knowledgeBase.js +118 -0
  123. package/dist/routers/members.d.ts +0 -41
  124. package/dist/routers/members.js +22 -710
  125. package/dist/routers/notes.d.ts +94 -0
  126. package/dist/routers/notes.js +37 -0
  127. package/dist/routers/notifications.js +7 -109
  128. package/dist/routers/payment.d.ts +2 -12
  129. package/dist/routers/payment.js +11 -393
  130. package/dist/routers/podcast.d.ts +1 -1
  131. package/dist/routers/podcast.js +11 -784
  132. package/dist/routers/studyguide.js +3 -129
  133. package/dist/routers/worksheets.d.ts +29 -14
  134. package/dist/routers/worksheets.js +49 -628
  135. package/dist/routers/workspace.d.ts +27 -71
  136. package/dist/routers/workspace.js +29 -922
  137. package/dist/scripts/purge-deleted-users.js +2 -2
  138. package/dist/server.js +10 -3
  139. package/dist/services/activity/activity-human-description.service.d.ts +13 -0
  140. package/dist/services/activity/activity-human-description.service.js +221 -0
  141. package/dist/services/activity/activity-human-description.service.test.d.ts +1 -0
  142. package/dist/services/activity/activity-human-description.service.test.js +16 -0
  143. package/dist/services/activity/activity-log.service.d.ts +87 -0
  144. package/dist/services/activity/activity-log.service.js +276 -0
  145. package/dist/services/activity/activity-log.service.test.d.ts +1 -0
  146. package/dist/services/activity/activity-log.service.test.js +27 -0
  147. package/dist/services/activity-human-description.service.d.ts +13 -0
  148. package/dist/services/activity-human-description.service.js +221 -0
  149. package/dist/services/activity-human-description.service.test.d.ts +1 -0
  150. package/dist/services/activity-human-description.service.test.js +16 -0
  151. package/dist/services/activity-log.service.d.ts +87 -0
  152. package/dist/services/activity-log.service.js +276 -0
  153. package/dist/services/activity-log.service.test.d.ts +1 -0
  154. package/dist/services/activity-log.service.test.js +27 -0
  155. package/dist/services/admin/admin.service.d.ts +270 -0
  156. package/dist/services/admin/admin.service.js +476 -0
  157. package/dist/services/admin.service.d.ts +270 -0
  158. package/dist/services/admin.service.js +476 -0
  159. package/dist/services/ai/ai-session.service.d.ts +5 -0
  160. package/dist/services/ai/ai-session.service.js +4 -0
  161. package/dist/services/ai-session.service.d.ts +60 -0
  162. package/dist/services/ai-session.service.js +561 -0
  163. package/dist/services/annotation.service.d.ts +177 -0
  164. package/dist/services/annotation.service.js +154 -0
  165. package/dist/services/artifact-notification.service.d.ts +14 -0
  166. package/dist/services/artifact-notification.service.js +20 -0
  167. package/dist/services/artifact-version.service.d.ts +38 -0
  168. package/dist/services/artifact-version.service.js +129 -0
  169. package/dist/services/artifacts/annotation.service.d.ts +177 -0
  170. package/dist/services/artifacts/annotation.service.js +154 -0
  171. package/dist/services/artifacts/artifact-version.service.d.ts +38 -0
  172. package/dist/services/artifacts/artifact-version.service.js +129 -0
  173. package/dist/services/artifacts/chat.service.d.ts +127 -0
  174. package/dist/services/artifacts/chat.service.js +182 -0
  175. package/dist/services/artifacts/study-guide.service.d.ts +18 -0
  176. package/dist/services/artifacts/study-guide.service.js +65 -0
  177. package/dist/services/auth/auth.service.d.ts +94 -0
  178. package/dist/services/auth/auth.service.js +368 -0
  179. package/dist/services/auth.service.d.ts +94 -0
  180. package/dist/services/auth.service.js +368 -0
  181. package/dist/services/base.service.d.ts +14 -0
  182. package/dist/services/base.service.js +14 -0
  183. package/dist/services/billing/payment.service.d.ts +44 -0
  184. package/dist/services/billing/payment.service.js +365 -0
  185. package/dist/services/billing/subscription.service.d.ts +37 -0
  186. package/dist/services/billing/subscription.service.js +654 -0
  187. package/dist/services/billing/usage.service.d.ts +47 -0
  188. package/dist/services/billing/usage.service.js +149 -0
  189. package/dist/services/chat.service.d.ts +127 -0
  190. package/dist/services/chat.service.js +182 -0
  191. package/dist/services/content/copilot.service.d.ts +113 -0
  192. package/dist/services/content/copilot.service.js +439 -0
  193. package/dist/services/content/flashcard-progress.service.d.ts +159 -0
  194. package/dist/services/content/flashcard-progress.service.js +432 -0
  195. package/dist/services/content/flashcard.service.d.ts +184 -0
  196. package/dist/services/content/flashcard.service.js +339 -0
  197. package/dist/services/content/media-analysis.service.d.ts +23 -0
  198. package/dist/services/content/media-analysis.service.js +404 -0
  199. package/dist/services/content/podcast.service.d.ts +267 -0
  200. package/dist/services/content/podcast.service.js +653 -0
  201. package/dist/services/content/worksheet-content.service.d.ts +37 -0
  202. package/dist/services/content/worksheet-content.service.js +84 -0
  203. package/dist/services/content/worksheet-content.service.test.d.ts +1 -0
  204. package/dist/services/content/worksheet-content.service.test.js +69 -0
  205. package/dist/services/content/worksheet-generation.service.d.ts +91 -0
  206. package/dist/services/content/worksheet-generation.service.js +95 -0
  207. package/dist/services/content/worksheet-generation.service.test.d.ts +1 -0
  208. package/dist/services/content/worksheet-generation.service.test.js +20 -0
  209. package/dist/services/content/worksheet.service.d.ts +347 -0
  210. package/dist/services/content/worksheet.service.js +599 -0
  211. package/dist/services/copilot.service.d.ts +116 -0
  212. package/dist/services/copilot.service.js +447 -0
  213. package/dist/services/flashcard-progress.service.d.ts +2 -2
  214. package/dist/services/flashcard-progress.service.js +3 -2
  215. package/dist/services/flashcard.service.d.ts +140 -0
  216. package/dist/services/flashcard.service.js +325 -0
  217. package/dist/services/invitation.service.d.ts +66 -0
  218. package/dist/services/invitation.service.js +348 -0
  219. package/dist/services/knowledge/knowledge-base.service.d.ts +316 -0
  220. package/dist/services/knowledge/knowledge-base.service.js +544 -0
  221. package/dist/services/knowledge-base.service.d.ts +316 -0
  222. package/dist/services/knowledge-base.service.js +536 -0
  223. package/dist/services/media-analysis.service.d.ts +23 -0
  224. package/dist/services/media-analysis.service.js +384 -0
  225. package/dist/services/member.service.d.ts +36 -0
  226. package/dist/services/member.service.js +193 -0
  227. package/dist/services/members/invitation.service.d.ts +66 -0
  228. package/dist/services/members/invitation.service.js +348 -0
  229. package/dist/services/members/member.service.d.ts +36 -0
  230. package/dist/services/members/member.service.js +193 -0
  231. package/dist/services/note.service.d.ts +55 -0
  232. package/dist/services/note.service.js +111 -0
  233. package/dist/services/notification.service.d.ts +214 -0
  234. package/dist/services/notification.service.js +550 -0
  235. package/dist/services/notification.service.test.d.ts +1 -0
  236. package/dist/services/notification.service.test.js +87 -0
  237. package/dist/services/notifications/notification.service.d.ts +214 -0
  238. package/dist/services/notifications/notification.service.js +550 -0
  239. package/dist/services/notifications/notification.service.test.d.ts +1 -0
  240. package/dist/services/notifications/notification.service.test.js +87 -0
  241. package/dist/services/payment.service.d.ts +55 -0
  242. package/dist/services/payment.service.js +368 -0
  243. package/dist/services/podcast.service.d.ts +267 -0
  244. package/dist/services/podcast.service.js +654 -0
  245. package/dist/services/router-module.service.d.ts +7 -0
  246. package/dist/services/router-module.service.js +10 -0
  247. package/dist/services/study-guide.service.d.ts +18 -0
  248. package/dist/services/study-guide.service.js +65 -0
  249. package/dist/services/subscription.service.d.ts +37 -0
  250. package/dist/services/subscription.service.js +654 -0
  251. package/dist/services/usage-limit-policy.service.d.ts +12 -0
  252. package/dist/services/usage-limit-policy.service.js +22 -0
  253. package/dist/services/usage-limit-policy.service.test.d.ts +1 -0
  254. package/dist/services/usage-limit-policy.service.test.js +46 -0
  255. package/dist/services/usage.service.d.ts +27 -0
  256. package/dist/services/usage.service.js +77 -0
  257. package/dist/services/worksheet-content.service.d.ts +42 -0
  258. package/dist/services/worksheet-content.service.js +84 -0
  259. package/dist/services/worksheet-content.service.test.d.ts +1 -0
  260. package/dist/services/worksheet-content.service.test.js +69 -0
  261. package/dist/services/worksheet-generation.service.d.ts +91 -0
  262. package/dist/services/worksheet-generation.service.js +95 -0
  263. package/dist/services/worksheet-generation.service.test.d.ts +1 -0
  264. package/dist/services/worksheet-generation.service.test.js +20 -0
  265. package/dist/services/worksheet.service.d.ts +385 -0
  266. package/dist/services/worksheet.service.js +596 -0
  267. package/dist/services/workspace/workspace-analytics.service.d.ts +24 -0
  268. package/dist/services/workspace/workspace-analytics.service.js +95 -0
  269. package/dist/services/workspace/workspace-kb.service.d.ts +40 -0
  270. package/dist/services/workspace/workspace-kb.service.js +184 -0
  271. package/dist/services/workspace/workspace.service.d.ts +263 -0
  272. package/dist/services/workspace/workspace.service.js +401 -0
  273. package/dist/services/workspace-analytics.service.d.ts +24 -0
  274. package/dist/services/workspace-analytics.service.js +95 -0
  275. package/dist/services/workspace-kb.service.d.ts +40 -0
  276. package/dist/services/workspace-kb.service.js +184 -0
  277. package/dist/services/workspace-progress.service.d.ts +27 -0
  278. package/dist/services/workspace-progress.service.js +56 -0
  279. package/dist/services/workspace-progress.service.test.d.ts +1 -0
  280. package/dist/services/workspace-progress.service.test.js +49 -0
  281. package/dist/services/workspace.service.d.ts +307 -0
  282. package/dist/services/workspace.service.js +390 -0
  283. package/dist/trpc.d.ts +12 -4
  284. package/dist/trpc.js +7 -13
  285. package/package.json +5 -6
  286. package/prisma/migrations/20260509000001_add_knowledge_base/migration.sql +99 -0
  287. package/prisma/migrations/20260509000002_curate_knowledge_base/migration.sql +52 -0
  288. package/prisma/migrations/20260522000000_add_notes/migration.sql +27 -0
  289. package/prisma/migrations/20260524000000_remove_notes/migration.sql +3 -0
  290. package/prisma/schema.prisma +150 -48
  291. package/prisma/seed.mjs +67 -0
  292. package/scripts/debug/README.md +4 -0
  293. package/src/README.md +63 -0
  294. package/src/context.ts +33 -3
  295. package/src/lib/ai/config.ts +34 -0
  296. package/src/lib/ai/embedding-client.ts +47 -0
  297. package/src/lib/ai/index.ts +65 -0
  298. package/src/lib/ai/inference-backend/client.ts +479 -0
  299. package/src/lib/ai/inference-backend/mocks.ts +171 -0
  300. package/src/lib/ai/inference-backend/types.ts +50 -0
  301. package/src/lib/ai/json-parse.ts +35 -0
  302. package/src/lib/ai/llm-client.ts +54 -0
  303. package/src/lib/ai/mock.ts +12 -0
  304. package/src/lib/ai/types.ts +11 -0
  305. package/src/lib/chunking.ts +81 -0
  306. package/src/lib/curated-kb-seed.ts +164 -0
  307. package/src/lib/email.ts +77 -115
  308. package/src/lib/embeddings.ts +9 -0
  309. package/src/lib/ensure-curated-kb-catalog.ts +60 -0
  310. package/src/lib/env.ts +2 -7
  311. package/src/lib/inference.ts +1 -21
  312. package/src/lib/kb-meta.ts +81 -0
  313. package/src/lib/pdf.ts +23 -0
  314. package/src/lib/workspace-kb.ts +7 -0
  315. package/src/repositories/artifact.repository.ts +55 -0
  316. package/src/repositories/base.repository.ts +19 -0
  317. package/src/repositories/invitation.repository.ts +53 -0
  318. package/src/repositories/notification.repository.ts +53 -0
  319. package/src/repositories/user.repository.ts +44 -0
  320. package/src/repositories/workspace-member.repository.ts +38 -0
  321. package/src/repositories/workspace.repository.ts +89 -0
  322. package/src/routers/_app.ts +4 -0
  323. package/src/routers/admin.ts +124 -692
  324. package/src/routers/annotations.ts +25 -203
  325. package/src/routers/artifactVersions.ts +32 -0
  326. package/src/routers/auth.ts +82 -520
  327. package/src/routers/chat.ts +42 -245
  328. package/src/routers/copilot.ts +41 -666
  329. package/src/routers/flashcards.ts +108 -404
  330. package/src/routers/knowledgeBase.ts +216 -0
  331. package/src/routers/members.ts +60 -782
  332. package/src/routers/notifications.ts +15 -117
  333. package/src/routers/payment.ts +37 -446
  334. package/src/routers/podcast.ts +36 -898
  335. package/src/routers/studyguide.ts +5 -144
  336. package/src/routers/worksheets.ts +171 -735
  337. package/src/routers/workspace.ts +141 -1108
  338. package/src/scripts/purge-deleted-users.ts +2 -2
  339. package/src/server.ts +10 -3
  340. package/src/{lib/activity_human_description.test.ts → services/activity/activity-human-description.service.test.ts} +1 -1
  341. package/src/{lib/activity_log_service.test.ts → services/activity/activity-log.service.test.ts} +1 -1
  342. package/src/{lib/activity_log_service.ts → services/activity/activity-log.service.ts} +2 -2
  343. package/src/services/admin/admin.service.ts +612 -0
  344. package/src/services/ai/ai-session.service.ts +5 -0
  345. package/src/services/artifacts/annotation.service.ts +189 -0
  346. package/src/services/artifacts/artifact-version.service.ts +151 -0
  347. package/src/services/artifacts/chat.service.ts +197 -0
  348. package/src/services/artifacts/study-guide.service.ts +72 -0
  349. package/src/services/auth/auth.service.ts +473 -0
  350. package/src/services/base.service.ts +19 -0
  351. package/src/services/billing/payment.service.ts +433 -0
  352. package/src/{lib/subscription_service.ts → services/billing/subscription.service.ts} +5 -5
  353. package/src/services/billing/usage.service.ts +207 -0
  354. package/src/services/content/copilot.service.ts +587 -0
  355. package/src/services/{flashcard-progress.service.ts → content/flashcard-progress.service.ts} +18 -12
  356. package/src/services/content/flashcard.service.ts +417 -0
  357. package/src/services/content/media-analysis.service.ts +561 -0
  358. package/src/services/content/podcast.service.ts +777 -0
  359. package/src/services/content/worksheet-content.service.test.ts +83 -0
  360. package/src/services/content/worksheet-content.service.ts +117 -0
  361. package/src/{lib/worksheet-generation.test.ts → services/content/worksheet-generation.service.test.ts} +3 -3
  362. package/src/services/content/worksheet.service.ts +751 -0
  363. package/src/services/knowledge/knowledge-base.service.ts +705 -0
  364. package/src/services/members/invitation.service.ts +427 -0
  365. package/src/services/members/member.service.ts +241 -0
  366. package/src/{lib/notification-service.test.ts → services/notifications/notification.service.test.ts} +2 -2
  367. package/src/{lib/notification-service.ts → services/notifications/notification.service.ts} +102 -1
  368. package/src/services/workspace/workspace-analytics.service.ts +107 -0
  369. package/src/services/workspace/workspace-kb.service.ts +273 -0
  370. package/src/services/workspace/workspace.service.ts +488 -0
  371. package/src/trpc.ts +7 -15
  372. package/src/lib/ai-session.ts +0 -704
  373. package/src/lib/usage_service.ts +0 -74
  374. package/src/lib/workspace-access.ts +0 -13
  375. /package/{check-difficulty.cjs → scripts/debug/check-difficulty.cjs} +0 -0
  376. /package/{check-questions.cjs → scripts/debug/check-questions.cjs} +0 -0
  377. /package/{db-summary.cjs → scripts/debug/db-summary.cjs} +0 -0
  378. /package/{mcq-test.cjs → scripts/debug/mcq-test.cjs} +0 -0
  379. /package/{test-generate.js → scripts/debug/test-generate.js} +0 -0
  380. /package/{test-ratio.cjs → scripts/debug/test-ratio.cjs} +0 -0
  381. /package/{zod-test.cjs → scripts/debug/zod-test.cjs} +0 -0
  382. /package/src/{lib/activity_human_description.ts → services/activity/activity-human-description.service.ts} +0 -0
  383. /package/src/{lib/worksheet-generation.ts → services/content/worksheet-generation.service.ts} +0 -0
@@ -0,0 +1,390 @@
1
+ import { TRPCError } from '@trpc/server';
2
+ import { BaseService } from './base.service.js';
3
+ import { ArtifactType } from '../lib/constants.js';
4
+ import { supabaseClient } from '../lib/storage.js';
5
+ import PusherService from '../lib/pusher.js';
6
+ import { aiSessionService } from './ai-session.service.js';
7
+ import { getUserStorageLimit } from './subscription.service.js';
8
+ import { notifyWorkspaceDeleted } from './notification.service.js';
9
+ export class WorkspaceService extends BaseService {
10
+ constructor(db) {
11
+ super(db);
12
+ }
13
+ async list(userId, parentId) {
14
+ const workspaces = await this.db.workspace.findMany({
15
+ where: { ownerId: userId, folderId: parentId },
16
+ orderBy: { updatedAt: 'desc' },
17
+ });
18
+ const folders = await this.db.folder.findMany({
19
+ where: { ownerId: userId, parentId },
20
+ });
21
+ return { workspaces, folders };
22
+ }
23
+ async getTree(userId) {
24
+ const allFolders = await this.db.folder.findMany({
25
+ where: { ownerId: userId },
26
+ orderBy: { updatedAt: 'desc' },
27
+ });
28
+ const allWorkspaces = await this.db.workspace.findMany({
29
+ where: { ownerId: userId },
30
+ include: {
31
+ uploads: {
32
+ select: {
33
+ id: true,
34
+ name: true,
35
+ mimeType: true,
36
+ createdAt: true,
37
+ },
38
+ },
39
+ },
40
+ orderBy: { updatedAt: 'desc' },
41
+ });
42
+ return { folders: allFolders, workspaces: allWorkspaces };
43
+ }
44
+ async create(userId, input) {
45
+ const ws = await this.db.workspace.create({
46
+ data: {
47
+ title: input.name,
48
+ description: input.description,
49
+ ownerId: userId,
50
+ folderId: input.parentId ?? null,
51
+ ...(input.markerColor !== undefined ? { markerColor: input.markerColor } : {}),
52
+ artifacts: {
53
+ create: {
54
+ type: ArtifactType.FLASHCARD_SET,
55
+ title: 'New Flashcard Set',
56
+ },
57
+ createMany: {
58
+ data: [
59
+ { type: ArtifactType.WORKSHEET, title: 'Worksheet 1' },
60
+ { type: ArtifactType.WORKSHEET, title: 'Worksheet 2' },
61
+ ],
62
+ },
63
+ },
64
+ },
65
+ });
66
+ await aiSessionService.initSession(ws.id, userId).catch((err) => {
67
+ this.logger.error('Failed to init AI session on workspace creation:', err);
68
+ });
69
+ await PusherService.emitLibraryUpdate(userId);
70
+ return ws;
71
+ }
72
+ async createFolder(userId, input) {
73
+ const folder = await this.db.folder.create({
74
+ data: {
75
+ name: input.name,
76
+ ownerId: userId,
77
+ color: input.color ?? '#9D00FF',
78
+ parentId: input.parentId ?? null,
79
+ },
80
+ });
81
+ await PusherService.emitLibraryUpdate(userId);
82
+ return folder;
83
+ }
84
+ async updateFolder(userId, input) {
85
+ const folder = await this.db.folder.update({
86
+ where: { id: input.id },
87
+ data: { name: input.name, markerColor: input.markerColor },
88
+ });
89
+ await PusherService.emitLibraryUpdate(userId);
90
+ return folder;
91
+ }
92
+ async deleteFolder(userId, id) {
93
+ const folder = await this.db.folder.delete({ where: { id } });
94
+ await PusherService.emitLibraryUpdate(userId);
95
+ return folder;
96
+ }
97
+ async get(userId, id) {
98
+ const ws = await this.db.workspace.findFirst({
99
+ where: { id, ownerId: userId },
100
+ include: {
101
+ artifacts: true,
102
+ folder: true,
103
+ uploads: true,
104
+ },
105
+ });
106
+ if (!ws)
107
+ throw new TRPCError({ code: 'NOT_FOUND' });
108
+ return ws;
109
+ }
110
+ async getStats(userId) {
111
+ const workspaces = await this.db.workspace.findMany({
112
+ where: {
113
+ OR: [{ ownerId: userId }, { sharedWith: { some: { id: userId } } }],
114
+ },
115
+ });
116
+ const folders = await this.db.folder.findMany({
117
+ where: { OR: [{ ownerId: userId }] },
118
+ });
119
+ const lastUpdated = await this.db.workspace.findFirst({
120
+ where: {
121
+ OR: [{ ownerId: userId }, { sharedWith: { some: { id: userId } } }],
122
+ },
123
+ orderBy: { updatedAt: 'desc' },
124
+ });
125
+ const spaceLeft = await this.db.fileAsset.aggregate({
126
+ where: { workspaceId: { in: workspaces.map((ws) => ws.id) }, userId },
127
+ _sum: { size: true },
128
+ });
129
+ const storageLimit = await getUserStorageLimit(userId);
130
+ return {
131
+ workspaces: workspaces.length,
132
+ folders: folders.length,
133
+ lastUpdated: lastUpdated?.updatedAt,
134
+ spaceUsed: spaceLeft._sum?.size ?? 0,
135
+ spaceTotal: storageLimit,
136
+ };
137
+ }
138
+ async update(userId, input) {
139
+ const existed = await this.db.workspace.findFirst({
140
+ where: { id: input.id, ownerId: userId },
141
+ });
142
+ if (!existed)
143
+ throw new TRPCError({ code: 'NOT_FOUND' });
144
+ const updated = await this.db.workspace.update({
145
+ where: { id: input.id },
146
+ data: {
147
+ title: input.name ?? existed.title,
148
+ description: input.description,
149
+ markerColor: input.markerColor !== undefined ? input.markerColor : existed.markerColor,
150
+ icon: input.icon ?? existed.icon,
151
+ },
152
+ });
153
+ await PusherService.emitLibraryUpdate(userId);
154
+ return updated;
155
+ }
156
+ async delete(userId, id) {
157
+ const workspaceToDelete = await this.db.workspace.findFirst({
158
+ where: { id, ownerId: userId },
159
+ select: {
160
+ id: true,
161
+ title: true,
162
+ ownerId: true,
163
+ members: { select: { userId: true } },
164
+ },
165
+ });
166
+ if (!workspaceToDelete)
167
+ throw new TRPCError({ code: 'NOT_FOUND' });
168
+ const actor = await this.db.user.findUnique({
169
+ where: { id: userId },
170
+ select: { name: true, email: true },
171
+ });
172
+ const actorName = actor?.name || actor?.email || 'A user';
173
+ await notifyWorkspaceDeleted(this.db, {
174
+ recipientUserIds: workspaceToDelete.members.map((m) => m.userId),
175
+ actorUserId: userId,
176
+ actorName,
177
+ workspaceId: workspaceToDelete.id,
178
+ workspaceTitle: workspaceToDelete.title,
179
+ });
180
+ const deleted = await this.db.workspace.deleteMany({
181
+ where: { id, ownerId: userId },
182
+ });
183
+ if (deleted.count === 0)
184
+ throw new TRPCError({ code: 'NOT_FOUND' });
185
+ await PusherService.emitLibraryUpdate(userId);
186
+ return true;
187
+ }
188
+ async getFolderInformation(userId, id) {
189
+ const folder = await this.db.folder.findFirst({
190
+ where: { id, ownerId: userId },
191
+ });
192
+ if (!folder)
193
+ throw new TRPCError({ code: 'NOT_FOUND' });
194
+ const parents = [];
195
+ let current = folder;
196
+ while (current.parentId) {
197
+ const parent = await this.db.folder.findFirst({
198
+ where: { id: current.parentId, ownerId: userId },
199
+ });
200
+ if (!parent)
201
+ break;
202
+ parents.push(parent);
203
+ current = parent;
204
+ }
205
+ return { folder, parents };
206
+ }
207
+ async getSharedWith(userId, id) {
208
+ const user = await this.db.user.findFirst({ where: { id: userId } });
209
+ if (!user || !user.email)
210
+ throw new TRPCError({ code: 'NOT_FOUND' });
211
+ const sharedWith = await this.db.workspace.findMany({
212
+ where: { members: { some: { userId } } },
213
+ });
214
+ const invitations = await this.db.workspaceInvitation.findMany({
215
+ where: { email: user.email, acceptedAt: null },
216
+ include: { workspace: true },
217
+ });
218
+ return { shared: sharedWith, invitations };
219
+ }
220
+ async uploadFiles(userId, input) {
221
+ const ws = await this.db.workspace.findFirst({
222
+ where: { id: input.id, ownerId: userId },
223
+ });
224
+ if (!ws)
225
+ throw new TRPCError({ code: 'NOT_FOUND' });
226
+ const workspaces = await this.db.workspace.findMany({
227
+ where: {
228
+ OR: [{ ownerId: userId }, { sharedWith: { some: { id: userId } } }],
229
+ },
230
+ });
231
+ const spaceUsed = await this.db.fileAsset.aggregate({
232
+ where: { workspaceId: { in: workspaces.map((w) => w.id) }, userId },
233
+ _sum: { size: true },
234
+ });
235
+ const storageLimit = await getUserStorageLimit(userId);
236
+ const totalSize = input.files.reduce((acc, file) => acc + file.size, 0);
237
+ if ((spaceUsed._sum?.size ?? 0) + totalSize > storageLimit) {
238
+ this.logger.warn(`Storage limit exceeded for user ${userId}. Used: ${spaceUsed._sum?.size}, Tried to upload: ${totalSize}, Limit: ${storageLimit}`);
239
+ throw new TRPCError({
240
+ code: 'FORBIDDEN',
241
+ message: `Storage limit exceeded. Maximum allowed storage is ${(storageLimit / (1024 * 1024 * 1024)).toFixed(1)}GB.`,
242
+ });
243
+ }
244
+ const results = [];
245
+ for (const file of input.files) {
246
+ const record = await this.db.fileAsset.create({
247
+ data: {
248
+ userId,
249
+ name: file.filename,
250
+ mimeType: file.contentType,
251
+ size: file.size,
252
+ workspaceId: input.id,
253
+ },
254
+ });
255
+ const objectKey = `${userId}/${record.id}-${file.filename}`;
256
+ const { data: signedUrlData, error: signedUrlError } = await supabaseClient.storage
257
+ .from('media')
258
+ .createSignedUploadUrl(objectKey);
259
+ if (signedUrlError) {
260
+ throw new TRPCError({
261
+ code: 'INTERNAL_SERVER_ERROR',
262
+ message: `Failed to upload file`,
263
+ });
264
+ }
265
+ await this.db.fileAsset.update({
266
+ where: { id: record.id },
267
+ data: {
268
+ bucket: 'media',
269
+ objectKey,
270
+ },
271
+ });
272
+ results.push({
273
+ fileId: record.id,
274
+ uploadUrl: signedUrlData.signedUrl,
275
+ });
276
+ }
277
+ return results;
278
+ }
279
+ async deleteFiles(userId, input) {
280
+ const files = await this.db.fileAsset.findMany({
281
+ where: {
282
+ id: { in: input.fileId },
283
+ workspaceId: input.id,
284
+ userId,
285
+ },
286
+ });
287
+ for (const file of files) {
288
+ if (file.bucket && file.objectKey) {
289
+ supabaseClient.storage
290
+ .from(file.bucket)
291
+ .remove([file.objectKey])
292
+ .catch((err) => {
293
+ this.logger.error(`Error deleting file ${file.objectKey} from bucket ${file.bucket}:`, err);
294
+ });
295
+ }
296
+ }
297
+ await this.db.fileAsset.deleteMany({
298
+ where: {
299
+ id: { in: input.fileId },
300
+ workspaceId: input.id,
301
+ userId,
302
+ },
303
+ });
304
+ return true;
305
+ }
306
+ async getFileUploadUrl(userId, input) {
307
+ const workspaces = await this.db.workspace.findMany({
308
+ where: {
309
+ OR: [{ ownerId: userId }, { sharedWith: { some: { id: userId } } }],
310
+ },
311
+ });
312
+ const spaceUsed = await this.db.fileAsset.aggregate({
313
+ where: { workspaceId: { in: workspaces.map((w) => w.id) }, userId },
314
+ _sum: { size: true },
315
+ });
316
+ const storageLimit = await getUserStorageLimit(userId);
317
+ if ((spaceUsed._sum?.size ?? 0) + input.size > storageLimit) {
318
+ this.logger.warn(`Storage limit exceeded for user ${userId}. Used: ${spaceUsed._sum?.size}, Tried to upload: ${input.size}, Limit: ${storageLimit}`);
319
+ throw new TRPCError({
320
+ code: 'FORBIDDEN',
321
+ message: `Storage limit exceeded. Maximum allowed storage is ${(storageLimit / (1024 * 1024 * 1024)).toFixed(1)}GB.`,
322
+ });
323
+ }
324
+ const objectKey = `workspace_${userId}/${input.workspaceId}-file_${input.filename}`;
325
+ const fileAsset = await this.db.fileAsset.create({
326
+ data: {
327
+ workspaceId: input.workspaceId,
328
+ name: input.filename,
329
+ mimeType: input.contentType,
330
+ size: input.size,
331
+ userId,
332
+ bucket: 'media',
333
+ objectKey,
334
+ },
335
+ });
336
+ const { data: signedUrlData, error: signedUrlError } = await supabaseClient.storage
337
+ .from('media')
338
+ .createSignedUploadUrl(objectKey, { upsert: true });
339
+ if (signedUrlError) {
340
+ this.logger.error('Signed upload URL error:', signedUrlError);
341
+ throw new TRPCError({
342
+ code: 'INTERNAL_SERVER_ERROR',
343
+ message: `Failed to create upload URL: ${signedUrlError.message}`,
344
+ });
345
+ }
346
+ await this.db.workspace.update({
347
+ where: { id: input.workspaceId },
348
+ data: { needsAnalysis: true },
349
+ });
350
+ return {
351
+ fileId: fileAsset.id,
352
+ uploadUrl: signedUrlData.signedUrl,
353
+ };
354
+ }
355
+ async search(userId, input) {
356
+ const { query, color } = input;
357
+ const workspaces = await this.db.workspace.findMany({
358
+ where: {
359
+ ownerId: userId,
360
+ markerColor: color || undefined,
361
+ ...(query
362
+ ? {
363
+ OR: [
364
+ { title: { contains: query, mode: 'insensitive' } },
365
+ { description: { contains: query, mode: 'insensitive' } },
366
+ ],
367
+ }
368
+ : {}),
369
+ },
370
+ orderBy: { updatedAt: 'desc' },
371
+ take: input.limit,
372
+ });
373
+ const folders = await this.db.folder.findMany({
374
+ where: {
375
+ ownerId: userId,
376
+ markerColor: color || undefined,
377
+ ...(query ? { name: { contains: query, mode: 'insensitive' } } : {}),
378
+ },
379
+ orderBy: { updatedAt: 'desc' },
380
+ take: input.limit,
381
+ });
382
+ const results = [
383
+ ...workspaces.map((w) => ({ ...w, type: 'workspace' })),
384
+ ...folders.map((f) => ({ ...f, type: 'folder', title: f.name })),
385
+ ]
386
+ .sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())
387
+ .slice(0, input.limit);
388
+ return results;
389
+ }
390
+ }
package/dist/trpc.d.ts CHANGED
@@ -20,7 +20,9 @@ export declare const publicProcedure: import("@trpc/server").TRPCProcedureBuilde
20
20
  /** Exported procedures with middleware */
21
21
  export declare const authedProcedure: import("@trpc/server").TRPCProcedureBuilder<Context, object, {
22
22
  userId: any;
23
- session: any;
23
+ session: {
24
+ user: import("./context.js").SessionUser;
25
+ };
24
26
  req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
25
27
  res: import("express").Response<any, Record<string, any>>;
26
28
  db: import("@prisma/client").PrismaClient<import("@prisma/client").Prisma.PrismaClientOptions, never, import("@prisma/client/runtime/library").DefaultArgs>;
@@ -28,7 +30,9 @@ export declare const authedProcedure: import("@trpc/server").TRPCProcedureBuilde
28
30
  }, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
29
31
  export declare const verifiedProcedure: import("@trpc/server").TRPCProcedureBuilder<Context, object, {
30
32
  userId: any;
31
- session: any;
33
+ session: {
34
+ user: import("./context.js").SessionUser;
35
+ };
32
36
  req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
33
37
  res: import("express").Response<any, Record<string, any>>;
34
38
  db: import("@prisma/client").PrismaClient<import("@prisma/client").Prisma.PrismaClientOptions, never, import("@prisma/client/runtime/library").DefaultArgs>;
@@ -36,7 +40,9 @@ export declare const verifiedProcedure: import("@trpc/server").TRPCProcedureBuil
36
40
  }, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
37
41
  export declare const adminProcedure: import("@trpc/server").TRPCProcedureBuilder<Context, object, {
38
42
  userId: any;
39
- session: any;
43
+ session: {
44
+ user: import("./context.js").SessionUser;
45
+ };
40
46
  req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
41
47
  res: import("express").Response<any, Record<string, any>>;
42
48
  db: import("@prisma/client").PrismaClient<import("@prisma/client").Prisma.PrismaClientOptions, never, import("@prisma/client/runtime/library").DefaultArgs>;
@@ -44,7 +50,9 @@ export declare const adminProcedure: import("@trpc/server").TRPCProcedureBuilder
44
50
  }, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, import("@trpc/server").TRPCUnsetMarker, false>;
45
51
  export declare const limitedProcedure: import("@trpc/server").TRPCProcedureBuilder<Context, object, {
46
52
  userId: any;
47
- session: any;
53
+ session: {
54
+ user: import("./context.js").SessionUser;
55
+ };
48
56
  req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
49
57
  res: import("express").Response<any, Record<string, any>>;
50
58
  db: import("@prisma/client").PrismaClient<import("@prisma/client").Prisma.PrismaClientOptions, never, import("@prisma/client/runtime/library").DefaultArgs>;
package/dist/trpc.js CHANGED
@@ -3,8 +3,8 @@ import superjson from "superjson";
3
3
  import { ActivityLogStatus } from "@prisma/client";
4
4
  import { logger } from "./lib/logger.js";
5
5
  import { toTRPCError } from "./lib/errors.js";
6
- import { getUserUsage, getUserPlanLimits } from "./lib/usage_service.js";
7
- import { getClientIp, isActivityLogEnabled, scheduleRecordActivity, truncateUserAgent, } from "./lib/activity_log_service.js";
6
+ import { getUserUsage, getUserPlanLimits } from "./services/billing/usage.service.js";
7
+ import { getClientIp, isActivityLogEnabled, scheduleRecordActivity, truncateUserAgent, } from "./services/activity/activity-log.service.js";
8
8
  /** Avoid logging the log viewers themselves (noise when browsing activity). */
9
9
  const SKIP_ACTIVITY_TRPC_PATHS = new Set([
10
10
  "admin.activityList",
@@ -79,11 +79,8 @@ const errorHandler = middleware(async ({ next }) => {
79
79
  /**
80
80
  * Middleware that enforces email verification
81
81
  */
82
- const isVerified = middleware(async ({ ctx, next }) => {
83
- const user = await ctx.db.user.findUnique({
84
- where: { id: ctx.session.user.id },
85
- select: { emailVerified: true },
86
- });
82
+ const isVerified = middleware(({ ctx, next }) => {
83
+ const user = ctx.session?.user;
87
84
  if (!user?.emailVerified) {
88
85
  throw new TRPCError({
89
86
  code: "FORBIDDEN",
@@ -139,12 +136,9 @@ const checkUsageLimit = middleware(async ({ ctx, next, path }) => {
139
136
  /**
140
137
  * Middleware that enforces system admin role
141
138
  */
142
- const isAdmin = middleware(async ({ ctx, next }) => {
143
- const user = await ctx.db.user.findUnique({
144
- where: { id: ctx.session.user.id },
145
- include: { role: true },
146
- });
147
- if (user?.role?.name !== 'System Admin') {
139
+ const isAdmin = middleware(({ ctx, next }) => {
140
+ const user = ctx.session?.user;
141
+ if (!user?.isSystemAdmin) {
148
142
  throw new TRPCError({
149
143
  code: "FORBIDDEN",
150
144
  message: "You do not have permission to access this resource",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goscribe/server",
3
- "version": "1.3.4",
3
+ "version": "1.6.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -15,8 +15,8 @@
15
15
  "dev": "tsx watch src/server.ts",
16
16
  "build": "npx prisma generate && tsc -p .",
17
17
  "start": "node --experimental-specifier-resolution=node dist/server.js",
18
- "test": "tsx --test src/lib/worksheet-generation.test.ts",
19
- "test:activity": "tsx --test src/lib/activity_log_service.test.ts src/lib/activity_human_description.test.ts",
18
+ "test": "tsx --test \"src/**/*.test.ts\"",
19
+ "test:activity": "tsx --test src/services/activity/activity-log.service.test.ts src/services/activity/activity-human-description.service.test.ts",
20
20
  "generate": "npx prisma generate",
21
21
  "prepublishOnly": "npm run generate && npm run build"
22
22
  },
@@ -42,8 +42,8 @@
42
42
  "express": "^5.1.0",
43
43
  "helmet": "^8.1.0",
44
44
  "morgan": "^1.10.1",
45
- "nodemailer": "^8.0.1",
46
45
  "openai": "^6.3.0",
46
+ "pdf-parse": "^1.1.4",
47
47
  "prisma": "^6.14.0",
48
48
  "pusher": "^5.2.0",
49
49
  "pusher-js": "^8.4.0",
@@ -61,7 +61,6 @@
61
61
  "@types/express": "^5.0.3",
62
62
  "@types/morgan": "^1.9.10",
63
63
  "@types/node": "^24.3.0",
64
- "@types/nodemailer": "^7.0.11",
65
64
  "ts-node": "^10.9.2",
66
65
  "ts-node-dev": "^2.0.0",
67
66
  "tsc-alias": "^1.8.16",
@@ -70,4 +69,4 @@
70
69
  "typescript": "^5.9.2",
71
70
  "typescript-transform-paths": "^3.5.5"
72
71
  }
73
- }
72
+ }
@@ -0,0 +1,99 @@
1
+ -- Knowledge Base feature: requires the pgvector extension for embedding storage.
2
+ -- See https://github.com/pgvector/pgvector
3
+ CREATE EXTENSION IF NOT EXISTS vector;
4
+
5
+ -- CreateEnum
6
+ CREATE TYPE "KnowledgeBaseStatus" AS ENUM ('READY', 'INDEXING', 'ERROR');
7
+
8
+ -- CreateEnum
9
+ CREATE TYPE "KnowledgeBaseDocumentStatus" AS ENUM ('PENDING', 'PROCESSING', 'READY', 'FAILED');
10
+
11
+ -- CreateTable
12
+ CREATE TABLE "KnowledgeBase" (
13
+ "id" TEXT NOT NULL,
14
+ "workspaceId" TEXT NOT NULL,
15
+ "createdById" TEXT,
16
+ "name" TEXT NOT NULL,
17
+ "description" TEXT,
18
+ "status" "KnowledgeBaseStatus" NOT NULL DEFAULT 'READY',
19
+ "embeddingModel" TEXT NOT NULL DEFAULT 'text-embedding-3-small',
20
+ "embeddingDim" INTEGER NOT NULL DEFAULT 1536,
21
+ "meta" JSONB,
22
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
23
+ "updatedAt" TIMESTAMP(3) NOT NULL,
24
+
25
+ CONSTRAINT "KnowledgeBase_pkey" PRIMARY KEY ("id")
26
+ );
27
+
28
+ -- CreateTable
29
+ CREATE TABLE "KnowledgeBaseDocument" (
30
+ "id" TEXT NOT NULL,
31
+ "knowledgeBaseId" TEXT NOT NULL,
32
+ "name" TEXT NOT NULL,
33
+ "mimeType" TEXT NOT NULL,
34
+ "size" INTEGER NOT NULL,
35
+ "bucket" TEXT,
36
+ "objectKey" TEXT,
37
+ "status" "KnowledgeBaseDocumentStatus" NOT NULL DEFAULT 'PENDING',
38
+ "errorMessage" TEXT,
39
+ "numChunks" INTEGER NOT NULL DEFAULT 0,
40
+ "numPages" INTEGER,
41
+ "meta" JSONB,
42
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
43
+ "updatedAt" TIMESTAMP(3) NOT NULL,
44
+
45
+ CONSTRAINT "KnowledgeBaseDocument_pkey" PRIMARY KEY ("id")
46
+ );
47
+
48
+ -- CreateTable
49
+ CREATE TABLE "KnowledgeBaseChunk" (
50
+ "id" TEXT NOT NULL,
51
+ "documentId" TEXT NOT NULL,
52
+ "knowledgeBaseId" TEXT NOT NULL,
53
+ "chunkIndex" INTEGER NOT NULL,
54
+ "pageNumber" INTEGER,
55
+ "content" TEXT NOT NULL,
56
+ "tokenCount" INTEGER,
57
+ "embedding" vector(1536),
58
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
59
+
60
+ CONSTRAINT "KnowledgeBaseChunk_pkey" PRIMARY KEY ("id")
61
+ );
62
+
63
+ -- CreateIndex
64
+ CREATE INDEX "KnowledgeBase_workspaceId_idx" ON "KnowledgeBase"("workspaceId");
65
+
66
+ -- CreateIndex
67
+ CREATE INDEX "KnowledgeBase_workspaceId_updatedAt_idx" ON "KnowledgeBase"("workspaceId", "updatedAt" DESC);
68
+
69
+ -- CreateIndex
70
+ CREATE INDEX "KnowledgeBaseDocument_knowledgeBaseId_idx" ON "KnowledgeBaseDocument"("knowledgeBaseId");
71
+
72
+ -- CreateIndex
73
+ CREATE INDEX "KnowledgeBaseDocument_knowledgeBaseId_createdAt_idx" ON "KnowledgeBaseDocument"("knowledgeBaseId", "createdAt" DESC);
74
+
75
+ -- CreateIndex
76
+ CREATE INDEX "KnowledgeBaseChunk_knowledgeBaseId_idx" ON "KnowledgeBaseChunk"("knowledgeBaseId");
77
+
78
+ -- CreateIndex
79
+ CREATE INDEX "KnowledgeBaseChunk_documentId_chunkIndex_idx" ON "KnowledgeBaseChunk"("documentId", "chunkIndex");
80
+
81
+ -- AddForeignKey
82
+ ALTER TABLE "KnowledgeBase" ADD CONSTRAINT "KnowledgeBase_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE CASCADE ON UPDATE CASCADE;
83
+
84
+ -- AddForeignKey
85
+ ALTER TABLE "KnowledgeBase" ADD CONSTRAINT "KnowledgeBase_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
86
+
87
+ -- AddForeignKey
88
+ ALTER TABLE "KnowledgeBaseDocument" ADD CONSTRAINT "KnowledgeBaseDocument_knowledgeBaseId_fkey" FOREIGN KEY ("knowledgeBaseId") REFERENCES "KnowledgeBase"("id") ON DELETE CASCADE ON UPDATE CASCADE;
89
+
90
+ -- AddForeignKey
91
+ ALTER TABLE "KnowledgeBaseChunk" ADD CONSTRAINT "KnowledgeBaseChunk_documentId_fkey" FOREIGN KEY ("documentId") REFERENCES "KnowledgeBaseDocument"("id") ON DELETE CASCADE ON UPDATE CASCADE;
92
+
93
+ -- ANN index for cosine similarity search across chunks (IVFFlat).
94
+ -- The number of lists (100) is a reasonable default for tens of thousands of
95
+ -- rows; tune via `SET ivfflat.probes` or recreate as the corpus grows.
96
+ CREATE INDEX IF NOT EXISTS "KnowledgeBaseChunk_embedding_cosine_idx"
97
+ ON "KnowledgeBaseChunk"
98
+ USING ivfflat ("embedding" vector_cosine_ops)
99
+ WITH (lists = 100);
@@ -0,0 +1,52 @@
1
+ -- Knowledge bases move from "owned by one workspace" to a global catalog
2
+ -- where workspaces opt-in via a join table. Curated KBs are discoverable
3
+ -- by users in the catalog search; non-curated ones are only attachable by
4
+ -- a System Admin.
5
+
6
+ -- 1. Drop the workspace-owns-KB relationship.
7
+ ALTER TABLE "KnowledgeBase" DROP CONSTRAINT IF EXISTS "KnowledgeBase_workspaceId_fkey";
8
+ DROP INDEX IF EXISTS "KnowledgeBase_workspaceId_idx";
9
+ DROP INDEX IF EXISTS "KnowledgeBase_workspaceId_updatedAt_idx";
10
+ ALTER TABLE "KnowledgeBase" DROP COLUMN IF EXISTS "workspaceId";
11
+
12
+ -- 2. Add the curated flag.
13
+ ALTER TABLE "KnowledgeBase"
14
+ ADD COLUMN IF NOT EXISTS "isCurated" BOOLEAN NOT NULL DEFAULT false;
15
+
16
+ CREATE INDEX IF NOT EXISTS "KnowledgeBase_isCurated_updatedAt_idx"
17
+ ON "KnowledgeBase" ("isCurated", "updatedAt" DESC);
18
+
19
+ -- 3. Create the workspace ↔ knowledge base join table.
20
+ CREATE TABLE IF NOT EXISTS "WorkspaceKnowledgeBase" (
21
+ "id" TEXT NOT NULL,
22
+ "workspaceId" TEXT NOT NULL,
23
+ "knowledgeBaseId" TEXT NOT NULL,
24
+ "addedById" TEXT,
25
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
26
+
27
+ CONSTRAINT "WorkspaceKnowledgeBase_pkey" PRIMARY KEY ("id")
28
+ );
29
+
30
+ CREATE UNIQUE INDEX IF NOT EXISTS "WorkspaceKnowledgeBase_workspaceId_knowledgeBaseId_key"
31
+ ON "WorkspaceKnowledgeBase" ("workspaceId", "knowledgeBaseId");
32
+
33
+ CREATE INDEX IF NOT EXISTS "WorkspaceKnowledgeBase_workspaceId_idx"
34
+ ON "WorkspaceKnowledgeBase" ("workspaceId");
35
+
36
+ CREATE INDEX IF NOT EXISTS "WorkspaceKnowledgeBase_knowledgeBaseId_idx"
37
+ ON "WorkspaceKnowledgeBase" ("knowledgeBaseId");
38
+
39
+ ALTER TABLE "WorkspaceKnowledgeBase"
40
+ ADD CONSTRAINT "WorkspaceKnowledgeBase_workspaceId_fkey"
41
+ FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id")
42
+ ON DELETE CASCADE ON UPDATE CASCADE;
43
+
44
+ ALTER TABLE "WorkspaceKnowledgeBase"
45
+ ADD CONSTRAINT "WorkspaceKnowledgeBase_knowledgeBaseId_fkey"
46
+ FOREIGN KEY ("knowledgeBaseId") REFERENCES "KnowledgeBase"("id")
47
+ ON DELETE CASCADE ON UPDATE CASCADE;
48
+
49
+ ALTER TABLE "WorkspaceKnowledgeBase"
50
+ ADD CONSTRAINT "WorkspaceKnowledgeBase_addedById_fkey"
51
+ FOREIGN KEY ("addedById") REFERENCES "User"("id")
52
+ ON DELETE SET NULL ON UPDATE CASCADE;