@goscribe/server 1.3.3 → 1.5.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 (378) 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/controllers/admin.controller.d.ts +715 -0
  6. package/dist/controllers/admin.controller.js +9 -0
  7. package/dist/controllers/annotations.controller.d.ts +439 -0
  8. package/dist/controllers/annotations.controller.js +9 -0
  9. package/dist/controllers/app-router.controller.d.ts +3011 -0
  10. package/dist/controllers/app-router.controller.js +38 -0
  11. package/dist/controllers/app-router.controller.test.d.ts +1 -0
  12. package/dist/controllers/app-router.controller.test.js +36 -0
  13. package/dist/controllers/auth.controller.d.ts +323 -0
  14. package/dist/controllers/auth.controller.js +9 -0
  15. package/dist/controllers/base.controller.d.ts +4 -0
  16. package/dist/controllers/base.controller.js +5 -0
  17. package/dist/controllers/chat.controller.d.ts +341 -0
  18. package/dist/controllers/chat.controller.js +9 -0
  19. package/dist/controllers/copilot.controller.d.ts +397 -0
  20. package/dist/controllers/copilot.controller.js +9 -0
  21. package/dist/controllers/flashcards.controller.d.ts +651 -0
  22. package/dist/controllers/flashcards.controller.js +9 -0
  23. package/dist/controllers/members.controller.d.ts +339 -0
  24. package/dist/controllers/members.controller.js +9 -0
  25. package/dist/controllers/notifications.controller.d.ts +199 -0
  26. package/dist/controllers/notifications.controller.js +9 -0
  27. package/dist/controllers/payment.controller.d.ts +181 -0
  28. package/dist/controllers/payment.controller.js +9 -0
  29. package/dist/controllers/podcast.controller.d.ts +575 -0
  30. package/dist/controllers/podcast.controller.js +9 -0
  31. package/dist/controllers/router-module.controller.d.ts +5 -0
  32. package/dist/controllers/router-module.controller.js +6 -0
  33. package/dist/controllers/studyguide.controller.d.ts +73 -0
  34. package/dist/controllers/studyguide.controller.js +9 -0
  35. package/dist/controllers/worksheets.controller.d.ts +829 -0
  36. package/dist/controllers/worksheets.controller.js +9 -0
  37. package/dist/controllers/workspace.controller.d.ts +1207 -0
  38. package/dist/controllers/workspace.controller.js +9 -0
  39. package/dist/lib/activity_human_description.test.js +16 -15
  40. package/dist/lib/activity_log_service.test.js +28 -23
  41. package/dist/lib/ai/config.d.ts +20 -0
  42. package/dist/lib/ai/config.js +31 -0
  43. package/dist/lib/ai/embedding-client.d.ts +8 -0
  44. package/dist/lib/ai/embedding-client.js +30 -0
  45. package/dist/lib/ai/index.d.ts +47 -0
  46. package/dist/lib/ai/index.js +28 -0
  47. package/dist/lib/ai/inference-backend/client.d.ts +28 -0
  48. package/dist/lib/ai/inference-backend/client.js +301 -0
  49. package/dist/lib/ai/inference-backend/mocks.d.ts +12 -0
  50. package/dist/lib/ai/inference-backend/mocks.js +133 -0
  51. package/dist/lib/ai/inference-backend/types.d.ts +44 -0
  52. package/dist/lib/ai/inference-backend/types.js +1 -0
  53. package/dist/lib/ai/json-parse.d.ts +2 -0
  54. package/dist/lib/ai/json-parse.js +34 -0
  55. package/dist/lib/ai/llm-client.d.ts +6 -0
  56. package/dist/lib/ai/llm-client.js +19 -0
  57. package/dist/lib/ai/mock.d.ts +2 -0
  58. package/dist/lib/ai/mock.js +10 -0
  59. package/dist/lib/ai/types.d.ts +9 -0
  60. package/dist/lib/ai/types.js +1 -0
  61. package/dist/lib/chunking.d.ts +19 -0
  62. package/dist/lib/chunking.js +47 -0
  63. package/dist/lib/curated-kb-seed.d.ts +12 -0
  64. package/dist/lib/curated-kb-seed.js +155 -0
  65. package/dist/lib/email.js +67 -108
  66. package/dist/lib/embeddings.d.ts +2 -0
  67. package/dist/lib/embeddings.js +1 -0
  68. package/dist/lib/ensure-curated-kb-catalog.d.ts +6 -0
  69. package/dist/lib/ensure-curated-kb-catalog.js +53 -0
  70. package/dist/lib/env.d.ts +1 -5
  71. package/dist/lib/env.js +2 -7
  72. package/dist/lib/inference.d.ts +1 -8
  73. package/dist/lib/inference.js +1 -19
  74. package/dist/lib/kb-meta.d.ts +8 -0
  75. package/dist/lib/kb-meta.js +77 -0
  76. package/dist/lib/note-text.d.ts +1 -0
  77. package/dist/lib/note-text.js +47 -0
  78. package/dist/lib/notification-service.test.js +37 -36
  79. package/dist/lib/pdf.d.ts +11 -0
  80. package/dist/lib/pdf.js +11 -0
  81. package/dist/lib/usage_service.d.ts +2 -1
  82. package/dist/lib/usage_service.js +30 -12
  83. package/dist/lib/worksheet-generation.js +4 -4
  84. package/dist/lib/worksheet-generation.test.js +32 -17
  85. package/dist/lib/workspace-kb.d.ts +5 -0
  86. package/dist/lib/workspace-kb.js +7 -0
  87. package/dist/models/controller-context.model.d.ts +8 -0
  88. package/dist/models/controller-context.model.js +1 -0
  89. package/dist/repositories/artifact.repository.d.ts +60 -0
  90. package/dist/repositories/artifact.repository.js +40 -0
  91. package/dist/repositories/base.repository.d.ts +14 -0
  92. package/dist/repositories/base.repository.js +14 -0
  93. package/dist/repositories/invitation.repository.d.ts +94 -0
  94. package/dist/repositories/invitation.repository.js +44 -0
  95. package/dist/repositories/notification.repository.d.ts +72 -0
  96. package/dist/repositories/notification.repository.js +44 -0
  97. package/dist/repositories/router-module.repository.d.ts +10 -0
  98. package/dist/repositories/router-module.repository.js +14 -0
  99. package/dist/repositories/user.repository.d.ts +74 -0
  100. package/dist/repositories/user.repository.js +37 -0
  101. package/dist/repositories/workspace-member.repository.d.ts +31 -0
  102. package/dist/repositories/workspace-member.repository.js +31 -0
  103. package/dist/repositories/workspace.repository.d.ts +97 -0
  104. package/dist/repositories/workspace.repository.js +79 -0
  105. package/dist/routers/_app.d.ts +528 -33
  106. package/dist/routers/_app.js +4 -0
  107. package/dist/routers/admin.d.ts +0 -4
  108. package/dist/routers/admin.js +21 -549
  109. package/dist/routers/annotations.js +12 -170
  110. package/dist/routers/artifactVersions.d.ts +65 -0
  111. package/dist/routers/artifactVersions.js +14 -0
  112. package/dist/routers/auth.d.ts +0 -6
  113. package/dist/routers/auth.js +36 -421
  114. package/dist/routers/chat.js +15 -229
  115. package/dist/routers/copilot.d.ts +14 -13
  116. package/dist/routers/copilot.js +13 -532
  117. package/dist/routers/flashcards.d.ts +5 -5
  118. package/dist/routers/flashcards.js +23 -349
  119. package/dist/routers/knowledgeBase.d.ts +421 -0
  120. package/dist/routers/knowledgeBase.js +118 -0
  121. package/dist/routers/members.d.ts +0 -41
  122. package/dist/routers/members.js +22 -710
  123. package/dist/routers/notes.d.ts +94 -0
  124. package/dist/routers/notes.js +37 -0
  125. package/dist/routers/notifications.js +7 -109
  126. package/dist/routers/payment.d.ts +3 -2
  127. package/dist/routers/payment.js +11 -393
  128. package/dist/routers/podcast.d.ts +1 -1
  129. package/dist/routers/podcast.js +11 -784
  130. package/dist/routers/studyguide.js +3 -129
  131. package/dist/routers/worksheets.d.ts +29 -14
  132. package/dist/routers/worksheets.js +49 -628
  133. package/dist/routers/workspace.d.ts +0 -4
  134. package/dist/routers/workspace.js +28 -922
  135. package/dist/scripts/purge-deleted-users.js +2 -2
  136. package/dist/server.js +10 -3
  137. package/dist/services/activity/activity-human-description.service.d.ts +13 -0
  138. package/dist/services/activity/activity-human-description.service.js +221 -0
  139. package/dist/services/activity/activity-human-description.service.test.d.ts +1 -0
  140. package/dist/services/activity/activity-human-description.service.test.js +16 -0
  141. package/dist/services/activity/activity-log.service.d.ts +87 -0
  142. package/dist/services/activity/activity-log.service.js +276 -0
  143. package/dist/services/activity/activity-log.service.test.d.ts +1 -0
  144. package/dist/services/activity/activity-log.service.test.js +27 -0
  145. package/dist/services/activity-human-description.service.d.ts +13 -0
  146. package/dist/services/activity-human-description.service.js +221 -0
  147. package/dist/services/activity-human-description.service.test.d.ts +1 -0
  148. package/dist/services/activity-human-description.service.test.js +16 -0
  149. package/dist/services/activity-log.service.d.ts +87 -0
  150. package/dist/services/activity-log.service.js +276 -0
  151. package/dist/services/activity-log.service.test.d.ts +1 -0
  152. package/dist/services/activity-log.service.test.js +27 -0
  153. package/dist/services/admin/admin.service.d.ts +270 -0
  154. package/dist/services/admin/admin.service.js +476 -0
  155. package/dist/services/admin.service.d.ts +270 -0
  156. package/dist/services/admin.service.js +476 -0
  157. package/dist/services/ai/ai-session.service.d.ts +5 -0
  158. package/dist/services/ai/ai-session.service.js +4 -0
  159. package/dist/services/ai-session.service.d.ts +60 -0
  160. package/dist/services/ai-session.service.js +561 -0
  161. package/dist/services/annotation.service.d.ts +177 -0
  162. package/dist/services/annotation.service.js +154 -0
  163. package/dist/services/artifact-notification.service.d.ts +14 -0
  164. package/dist/services/artifact-notification.service.js +20 -0
  165. package/dist/services/artifact-version.service.d.ts +38 -0
  166. package/dist/services/artifact-version.service.js +129 -0
  167. package/dist/services/artifacts/annotation.service.d.ts +177 -0
  168. package/dist/services/artifacts/annotation.service.js +154 -0
  169. package/dist/services/artifacts/artifact-version.service.d.ts +38 -0
  170. package/dist/services/artifacts/artifact-version.service.js +129 -0
  171. package/dist/services/artifacts/chat.service.d.ts +127 -0
  172. package/dist/services/artifacts/chat.service.js +182 -0
  173. package/dist/services/artifacts/study-guide.service.d.ts +18 -0
  174. package/dist/services/artifacts/study-guide.service.js +65 -0
  175. package/dist/services/auth/auth.service.d.ts +94 -0
  176. package/dist/services/auth/auth.service.js +368 -0
  177. package/dist/services/auth.service.d.ts +94 -0
  178. package/dist/services/auth.service.js +368 -0
  179. package/dist/services/base.service.d.ts +14 -0
  180. package/dist/services/base.service.js +14 -0
  181. package/dist/services/billing/payment.service.d.ts +55 -0
  182. package/dist/services/billing/payment.service.js +368 -0
  183. package/dist/services/billing/subscription.service.d.ts +37 -0
  184. package/dist/services/billing/subscription.service.js +654 -0
  185. package/dist/services/billing/usage.service.d.ts +27 -0
  186. package/dist/services/billing/usage.service.js +77 -0
  187. package/dist/services/chat.service.d.ts +127 -0
  188. package/dist/services/chat.service.js +182 -0
  189. package/dist/services/content/copilot.service.d.ts +113 -0
  190. package/dist/services/content/copilot.service.js +453 -0
  191. package/dist/services/content/flashcard-progress.service.d.ts +159 -0
  192. package/dist/services/content/flashcard-progress.service.js +432 -0
  193. package/dist/services/content/flashcard.service.d.ts +140 -0
  194. package/dist/services/content/flashcard.service.js +326 -0
  195. package/dist/services/content/media-analysis.service.d.ts +23 -0
  196. package/dist/services/content/media-analysis.service.js +404 -0
  197. package/dist/services/content/podcast.service.d.ts +267 -0
  198. package/dist/services/content/podcast.service.js +653 -0
  199. package/dist/services/content/worksheet-content.service.d.ts +37 -0
  200. package/dist/services/content/worksheet-content.service.js +84 -0
  201. package/dist/services/content/worksheet-content.service.test.d.ts +1 -0
  202. package/dist/services/content/worksheet-content.service.test.js +69 -0
  203. package/dist/services/content/worksheet-generation.service.d.ts +91 -0
  204. package/dist/services/content/worksheet-generation.service.js +95 -0
  205. package/dist/services/content/worksheet-generation.service.test.d.ts +1 -0
  206. package/dist/services/content/worksheet-generation.service.test.js +20 -0
  207. package/dist/services/content/worksheet.service.d.ts +347 -0
  208. package/dist/services/content/worksheet.service.js +599 -0
  209. package/dist/services/copilot.service.d.ts +116 -0
  210. package/dist/services/copilot.service.js +447 -0
  211. package/dist/services/flashcard-progress.service.d.ts +2 -2
  212. package/dist/services/flashcard-progress.service.js +3 -2
  213. package/dist/services/flashcard.service.d.ts +140 -0
  214. package/dist/services/flashcard.service.js +325 -0
  215. package/dist/services/invitation.service.d.ts +66 -0
  216. package/dist/services/invitation.service.js +348 -0
  217. package/dist/services/knowledge/knowledge-base.service.d.ts +316 -0
  218. package/dist/services/knowledge/knowledge-base.service.js +544 -0
  219. package/dist/services/knowledge-base.service.d.ts +316 -0
  220. package/dist/services/knowledge-base.service.js +536 -0
  221. package/dist/services/media-analysis.service.d.ts +23 -0
  222. package/dist/services/media-analysis.service.js +384 -0
  223. package/dist/services/member.service.d.ts +36 -0
  224. package/dist/services/member.service.js +193 -0
  225. package/dist/services/members/invitation.service.d.ts +66 -0
  226. package/dist/services/members/invitation.service.js +348 -0
  227. package/dist/services/members/member.service.d.ts +36 -0
  228. package/dist/services/members/member.service.js +193 -0
  229. package/dist/services/note.service.d.ts +55 -0
  230. package/dist/services/note.service.js +111 -0
  231. package/dist/services/notification.service.d.ts +214 -0
  232. package/dist/services/notification.service.js +550 -0
  233. package/dist/services/notification.service.test.d.ts +1 -0
  234. package/dist/services/notification.service.test.js +87 -0
  235. package/dist/services/notifications/notification.service.d.ts +214 -0
  236. package/dist/services/notifications/notification.service.js +550 -0
  237. package/dist/services/notifications/notification.service.test.d.ts +1 -0
  238. package/dist/services/notifications/notification.service.test.js +87 -0
  239. package/dist/services/payment.service.d.ts +55 -0
  240. package/dist/services/payment.service.js +368 -0
  241. package/dist/services/podcast.service.d.ts +267 -0
  242. package/dist/services/podcast.service.js +654 -0
  243. package/dist/services/router-module.service.d.ts +7 -0
  244. package/dist/services/router-module.service.js +10 -0
  245. package/dist/services/study-guide.service.d.ts +18 -0
  246. package/dist/services/study-guide.service.js +65 -0
  247. package/dist/services/subscription.service.d.ts +37 -0
  248. package/dist/services/subscription.service.js +654 -0
  249. package/dist/services/usage-limit-policy.service.d.ts +12 -0
  250. package/dist/services/usage-limit-policy.service.js +22 -0
  251. package/dist/services/usage-limit-policy.service.test.d.ts +1 -0
  252. package/dist/services/usage-limit-policy.service.test.js +46 -0
  253. package/dist/services/usage.service.d.ts +27 -0
  254. package/dist/services/usage.service.js +77 -0
  255. package/dist/services/worksheet-content.service.d.ts +42 -0
  256. package/dist/services/worksheet-content.service.js +84 -0
  257. package/dist/services/worksheet-content.service.test.d.ts +1 -0
  258. package/dist/services/worksheet-content.service.test.js +69 -0
  259. package/dist/services/worksheet-generation.service.d.ts +91 -0
  260. package/dist/services/worksheet-generation.service.js +95 -0
  261. package/dist/services/worksheet-generation.service.test.d.ts +1 -0
  262. package/dist/services/worksheet-generation.service.test.js +20 -0
  263. package/dist/services/worksheet.service.d.ts +385 -0
  264. package/dist/services/worksheet.service.js +596 -0
  265. package/dist/services/workspace/workspace-analytics.service.d.ts +24 -0
  266. package/dist/services/workspace/workspace-analytics.service.js +95 -0
  267. package/dist/services/workspace/workspace-kb.service.d.ts +40 -0
  268. package/dist/services/workspace/workspace-kb.service.js +184 -0
  269. package/dist/services/workspace/workspace.service.d.ts +307 -0
  270. package/dist/services/workspace/workspace.service.js +394 -0
  271. package/dist/services/workspace-analytics.service.d.ts +24 -0
  272. package/dist/services/workspace-analytics.service.js +95 -0
  273. package/dist/services/workspace-kb.service.d.ts +40 -0
  274. package/dist/services/workspace-kb.service.js +184 -0
  275. package/dist/services/workspace-progress.service.d.ts +27 -0
  276. package/dist/services/workspace-progress.service.js +56 -0
  277. package/dist/services/workspace-progress.service.test.d.ts +1 -0
  278. package/dist/services/workspace-progress.service.test.js +49 -0
  279. package/dist/services/workspace.service.d.ts +307 -0
  280. package/dist/services/workspace.service.js +390 -0
  281. package/dist/trpc.js +2 -2
  282. package/package.json +5 -6
  283. package/prisma/migrations/20260509000001_add_knowledge_base/migration.sql +99 -0
  284. package/prisma/migrations/20260509000002_curate_knowledge_base/migration.sql +52 -0
  285. package/prisma/migrations/20260522000000_add_notes/migration.sql +27 -0
  286. package/prisma/migrations/20260524000000_remove_notes/migration.sql +3 -0
  287. package/prisma/schema.prisma +150 -48
  288. package/prisma/seed.mjs +67 -0
  289. package/scripts/debug/README.md +4 -0
  290. package/src/README.md +63 -0
  291. package/src/lib/ai/config.ts +34 -0
  292. package/src/lib/ai/embedding-client.ts +47 -0
  293. package/src/lib/ai/index.ts +62 -0
  294. package/src/lib/ai/inference-backend/client.ts +479 -0
  295. package/src/lib/ai/inference-backend/mocks.ts +171 -0
  296. package/src/lib/ai/inference-backend/types.ts +50 -0
  297. package/src/lib/ai/json-parse.ts +35 -0
  298. package/src/lib/ai/llm-client.ts +31 -0
  299. package/src/lib/ai/mock.ts +12 -0
  300. package/src/lib/ai/types.ts +11 -0
  301. package/src/lib/chunking.ts +81 -0
  302. package/src/lib/curated-kb-seed.ts +164 -0
  303. package/src/lib/email.ts +77 -115
  304. package/src/lib/embeddings.ts +9 -0
  305. package/src/lib/ensure-curated-kb-catalog.ts +60 -0
  306. package/src/lib/env.ts +2 -7
  307. package/src/lib/inference.ts +1 -21
  308. package/src/lib/kb-meta.ts +81 -0
  309. package/src/lib/pdf.ts +23 -0
  310. package/src/lib/workspace-kb.ts +7 -0
  311. package/src/repositories/artifact.repository.ts +55 -0
  312. package/src/repositories/base.repository.ts +19 -0
  313. package/src/repositories/invitation.repository.ts +53 -0
  314. package/src/repositories/notification.repository.ts +53 -0
  315. package/src/repositories/user.repository.ts +44 -0
  316. package/src/repositories/workspace-member.repository.ts +38 -0
  317. package/src/repositories/workspace.repository.ts +89 -0
  318. package/src/routers/_app.ts +4 -0
  319. package/src/routers/admin.ts +124 -692
  320. package/src/routers/annotations.ts +25 -203
  321. package/src/routers/artifactVersions.ts +32 -0
  322. package/src/routers/auth.ts +81 -519
  323. package/src/routers/chat.ts +42 -245
  324. package/src/routers/copilot.ts +41 -666
  325. package/src/routers/flashcards.ts +108 -404
  326. package/src/routers/knowledgeBase.ts +216 -0
  327. package/src/routers/members.ts +60 -782
  328. package/src/routers/notifications.ts +15 -117
  329. package/src/routers/payment.ts +37 -446
  330. package/src/routers/podcast.ts +36 -898
  331. package/src/routers/studyguide.ts +5 -144
  332. package/src/routers/worksheets.ts +171 -735
  333. package/src/routers/workspace.ts +138 -1109
  334. package/src/scripts/purge-deleted-users.ts +2 -2
  335. package/src/server.ts +10 -3
  336. package/src/{lib/activity_human_description.test.ts → services/activity/activity-human-description.service.test.ts} +1 -1
  337. package/src/{lib/activity_log_service.test.ts → services/activity/activity-log.service.test.ts} +1 -1
  338. package/src/{lib/activity_log_service.ts → services/activity/activity-log.service.ts} +2 -2
  339. package/src/services/admin/admin.service.ts +612 -0
  340. package/src/services/ai/ai-session.service.ts +5 -0
  341. package/src/services/artifacts/annotation.service.ts +189 -0
  342. package/src/services/artifacts/artifact-version.service.ts +151 -0
  343. package/src/services/artifacts/chat.service.ts +197 -0
  344. package/src/services/artifacts/study-guide.service.ts +72 -0
  345. package/src/services/auth/auth.service.ts +473 -0
  346. package/src/services/base.service.ts +19 -0
  347. package/src/services/billing/payment.service.ts +436 -0
  348. package/src/{lib/subscription_service.ts → services/billing/subscription.service.ts} +5 -5
  349. package/src/{lib/usage_service.ts → services/billing/usage.service.ts} +32 -12
  350. package/src/services/content/copilot.service.ts +596 -0
  351. package/src/services/{flashcard-progress.service.ts → content/flashcard-progress.service.ts} +6 -3
  352. package/src/services/content/flashcard.service.ts +394 -0
  353. package/src/services/content/media-analysis.service.ts +556 -0
  354. package/src/services/content/podcast.service.ts +777 -0
  355. package/src/services/content/worksheet-content.service.test.ts +83 -0
  356. package/src/services/content/worksheet-content.service.ts +117 -0
  357. package/src/{lib/worksheet-generation.test.ts → services/content/worksheet-generation.service.test.ts} +1 -1
  358. package/src/services/content/worksheet.service.ts +751 -0
  359. package/src/services/knowledge/knowledge-base.service.ts +705 -0
  360. package/src/services/members/invitation.service.ts +427 -0
  361. package/src/services/members/member.service.ts +241 -0
  362. package/src/{lib/notification-service.test.ts → services/notifications/notification.service.test.ts} +2 -2
  363. package/src/{lib/notification-service.ts → services/notifications/notification.service.ts} +102 -1
  364. package/src/services/workspace/workspace-analytics.service.ts +107 -0
  365. package/src/services/workspace/workspace-kb.service.ts +273 -0
  366. package/src/services/workspace/workspace.service.ts +481 -0
  367. package/src/trpc.ts +2 -2
  368. package/src/lib/ai-session.ts +0 -704
  369. package/src/lib/workspace-access.ts +0 -13
  370. /package/{check-difficulty.cjs → scripts/debug/check-difficulty.cjs} +0 -0
  371. /package/{check-questions.cjs → scripts/debug/check-questions.cjs} +0 -0
  372. /package/{db-summary.cjs → scripts/debug/db-summary.cjs} +0 -0
  373. /package/{mcq-test.cjs → scripts/debug/mcq-test.cjs} +0 -0
  374. /package/{test-generate.js → scripts/debug/test-generate.js} +0 -0
  375. /package/{test-ratio.cjs → scripts/debug/test-ratio.cjs} +0 -0
  376. /package/{zod-test.cjs → scripts/debug/zod-test.cjs} +0 -0
  377. /package/src/{lib/activity_human_description.ts → services/activity/activity-human-description.service.ts} +0 -0
  378. /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.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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goscribe/server",
3
- "version": "1.3.3",
3
+ "version": "1.5.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;
@@ -0,0 +1,27 @@
1
+ -- Workspace notes (Notion-style block editor content per user/workspace).
2
+
3
+ CREATE TABLE "Note" (
4
+ "id" TEXT NOT NULL,
5
+ "workspaceId" TEXT NOT NULL,
6
+ "userId" TEXT NOT NULL,
7
+ "title" TEXT NOT NULL DEFAULT 'Untitled',
8
+ "emoji" TEXT NOT NULL DEFAULT '📝',
9
+ "blocks" JSONB NOT NULL DEFAULT '[]',
10
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
11
+ "updatedAt" TIMESTAMP(3) NOT NULL,
12
+
13
+ CONSTRAINT "Note_pkey" PRIMARY KEY ("id")
14
+ );
15
+
16
+ CREATE INDEX "Note_workspaceId_userId_updatedAt_idx"
17
+ ON "Note"("workspaceId", "userId", "updatedAt" DESC);
18
+
19
+ ALTER TABLE "Note"
20
+ ADD CONSTRAINT "Note_workspaceId_fkey"
21
+ FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id")
22
+ ON DELETE CASCADE ON UPDATE CASCADE;
23
+
24
+ ALTER TABLE "Note"
25
+ ADD CONSTRAINT "Note_userId_fkey"
26
+ FOREIGN KEY ("userId") REFERENCES "User"("id")
27
+ ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,3 @@
1
+ -- Drop workspace notes table (feature removed).
2
+
3
+ DROP TABLE IF EXISTS "Note";