@goscribe/server 1.3.4 → 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
@@ -1,4 +1,13 @@
1
1
  import { prisma } from './prisma.js';
2
+ const FALLBACK_PLAN_LIMITS = {
3
+ id: 'fallback-free',
4
+ planId: 'fallback-free',
5
+ maxStorageBytes: BigInt(1024 * 1024 * 1024), // 1GB
6
+ maxWorksheets: 3,
7
+ maxFlashcards: 20,
8
+ maxPodcasts: 0,
9
+ maxStudyGuides: 1,
10
+ };
2
11
  /**
3
12
  * Counts all resources consumed by a user across the platform.
4
13
  */
@@ -26,34 +35,43 @@ export async function getUserUsage(userId) {
26
35
  * PLUS any extra credits purchased.
27
36
  */
28
37
  export async function getUserPlanLimits(userId) {
29
- const [activeSub, userCredits] = await Promise.all([
38
+ const [activeSub, freePlan, userCredits] = await Promise.all([
30
39
  prisma.subscription.findFirst({
31
40
  where: { userId, status: 'active' },
32
41
  include: { plan: { include: { limit: true } } },
33
42
  orderBy: { createdAt: 'desc' }
34
43
  }),
44
+ prisma.plan.findFirst({
45
+ where: {
46
+ active: true,
47
+ price: 0,
48
+ limit: { isNot: null }
49
+ },
50
+ include: { limit: true },
51
+ orderBy: { createdAt: 'asc' }
52
+ }),
35
53
  prisma.userCredit.groupBy({
36
54
  by: ['resourceType'],
37
55
  where: { userId },
38
56
  _sum: { amount: true }
39
57
  })
40
58
  ]);
41
- const baseLimit = activeSub?.plan?.limit;
42
- // If no active subscription and no credits, user has no active limits
43
- if (!baseLimit && userCredits.length === 0)
44
- return null;
59
+ const baseLimit = activeSub?.plan?.limit ?? freePlan?.limit;
60
+ // Prefer subscription limits, then DB free-plan limits, then hardcoded safety fallback.
61
+ const base = baseLimit ?? FALLBACK_PLAN_LIMITS;
45
62
  // Fast lookup for credits
46
63
  const getCreditSum = (type) => userCredits.find(c => c.resourceType === type)?._sum.amount || 0;
47
64
  // Return the merged total limit
48
65
  return {
49
- id: baseLimit?.id || 'credits-only',
50
- planId: baseLimit?.planId || 'credits-only',
51
- maxStorageBytes: BigInt(Number(baseLimit?.maxStorageBytes || 0) + (getCreditSum('STORAGE') * 1024 * 1024)),
52
- maxWorksheets: (baseLimit?.maxWorksheets || 0) + getCreditSum('WORKSHEET'),
53
- maxFlashcards: (baseLimit?.maxFlashcards || 0) + getCreditSum('FLASHCARD_SET'),
54
- maxPodcasts: (baseLimit?.maxPodcasts || 0) + getCreditSum('PODCAST_EPISODE'),
55
- maxStudyGuides: (baseLimit?.maxStudyGuides || 0) + getCreditSum('STUDY_GUIDE'),
66
+ id: base.id,
67
+ planId: base.planId,
68
+ maxStorageBytes: BigInt(Number(base.maxStorageBytes) + (getCreditSum('STORAGE') * 1024 * 1024)),
69
+ maxWorksheets: base.maxWorksheets + getCreditSum('WORKSHEET'),
70
+ maxFlashcards: base.maxFlashcards + getCreditSum('FLASHCARD_SET'),
71
+ maxPodcasts: base.maxPodcasts + getCreditSum('PODCAST_EPISODE'),
72
+ maxStudyGuides: base.maxStudyGuides + getCreditSum('STUDY_GUIDE'),
56
73
  createdAt: baseLimit?.createdAt || new Date(),
57
74
  updatedAt: baseLimit?.updatedAt || new Date(),
75
+ isFallbackPlan: !baseLimit,
58
76
  };
59
77
  }
@@ -26,16 +26,16 @@ export function parsePresetConfig(raw) {
26
26
  return worksheetPresetConfigSchema.parse(raw);
27
27
  }
28
28
  export function mergeWorksheetGenerationConfig(presetConfig, configOverride, legacy) {
29
- // Precedence: legacy flat fields > configOverride > preset > defaults
30
- // We place legacy AFTER configOverride because configOverride's Zod partial schema injects defaults (like medium)
31
- // that shouldn't overwrite explicit explicit user choices passing via legacy parameters.
29
+ // Precedence: configOverride > legacy flat fields > preset > defaults.
30
+ // An explicit configOverride from the caller always wins over the router's
31
+ // legacy top-level fields (which have zod defaults like 'medium').
32
32
  const merged = {
33
33
  ...defaultConfig,
34
34
  ...presetConfig,
35
- ...configOverride,
36
35
  ...(legacy.numQuestions !== undefined ? { numQuestions: legacy.numQuestions } : {}),
37
36
  ...(legacy.difficulty !== undefined ? { difficulty: legacy.difficulty } : {}),
38
37
  ...(legacy.mode !== undefined ? { mode: legacy.mode } : {}),
38
+ ...configOverride,
39
39
  };
40
40
  return worksheetPresetConfigSchema.parse(merged);
41
41
  }
@@ -1,20 +1,35 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
1
+ import { describe, it, expect } from 'vitest';
3
2
  import { mergeWorksheetGenerationConfig, normalizeWorksheetProblemForDb } from './worksheet-generation.js';
4
- test('mergeWorksheetGenerationConfig: override beats preset and legacy', () => {
5
- const r = mergeWorksheetGenerationConfig({ mode: 'practice', numQuestions: 5, difficulty: 'easy' }, { mode: 'quiz', numQuestions: 10, difficulty: 'medium' }, { numQuestions: 3, difficulty: 'hard' });
6
- assert.equal(r.mode, 'quiz');
7
- assert.equal(r.numQuestions, 10);
8
- assert.equal(r.difficulty, 'medium');
3
+ describe('mergeWorksheetGenerationConfig', () => {
4
+ it('override beats preset and legacy', () => {
5
+ const r = mergeWorksheetGenerationConfig({ mode: 'practice', numQuestions: 5, difficulty: 'easy' }, { mode: 'quiz', numQuestions: 10, difficulty: 'medium' }, { numQuestions: 3, difficulty: 'hard' });
6
+ expect(r.mode).toBe('quiz');
7
+ expect(r.numQuestions).toBe(10);
8
+ expect(r.difficulty).toBe('medium');
9
+ });
10
+ it('legacy beats preset when no override', () => {
11
+ const r = mergeWorksheetGenerationConfig({ mode: 'practice', numQuestions: 5, difficulty: 'easy' }, undefined, { numQuestions: 7, difficulty: 'hard' });
12
+ expect(r.numQuestions).toBe(7);
13
+ expect(r.difficulty).toBe('hard');
14
+ expect(r.mode).toBe('practice');
15
+ });
16
+ it('preset supplies defaults when override and legacy absent', () => {
17
+ const r = mergeWorksheetGenerationConfig({ mode: 'quiz', numQuestions: 5, difficulty: 'easy' }, undefined, {});
18
+ expect(r.mode).toBe('quiz');
19
+ expect(r.numQuestions).toBe(5);
20
+ expect(r.difficulty).toBe('easy');
21
+ });
9
22
  });
10
- test('normalizeWorksheetProblemForDb coerces MCQ answer to option index', () => {
11
- const row = normalizeWorksheetProblemForDb({
12
- question: 'Capital of France?',
13
- answer: 'Paris',
14
- type: 'MULTIPLE_CHOICE',
15
- options: ['London', 'Paris', 'Berlin'],
16
- }, 0, 'MEDIUM', true);
17
- assert.equal(row.type, 'MULTIPLE_CHOICE');
18
- assert.equal(row.answer, '1');
19
- assert.ok(row.meta.options && row.meta.options.length >= 2);
23
+ describe('normalizeWorksheetProblemForDb', () => {
24
+ it('coerces MCQ answer to option index', () => {
25
+ const row = normalizeWorksheetProblemForDb({
26
+ question: 'Capital of France?',
27
+ answer: 'Paris',
28
+ type: 'MULTIPLE_CHOICE',
29
+ options: ['London', 'Paris', 'Berlin'],
30
+ }, 0, 'MEDIUM', true);
31
+ expect(row.type).toBe('MULTIPLE_CHOICE');
32
+ expect(row.answer).toBe('1');
33
+ expect(row.meta.options?.length).toBeGreaterThanOrEqual(2);
34
+ });
20
35
  });
@@ -0,0 +1,5 @@
1
+ /** Meta.kind value for the private, auto-managed KB attached to each workspace. */
2
+ export declare const WORKSPACE_KB_KIND = "workspace";
3
+ export declare function isWorkspaceManagedKb(kb: {
4
+ meta: unknown;
5
+ }): boolean;
@@ -0,0 +1,7 @@
1
+ /** Meta.kind value for the private, auto-managed KB attached to each workspace. */
2
+ export const WORKSPACE_KB_KIND = 'workspace';
3
+ export function isWorkspaceManagedKb(kb) {
4
+ if (!kb.meta || typeof kb.meta !== 'object')
5
+ return false;
6
+ return kb.meta.kind === WORKSPACE_KB_KIND;
7
+ }
@@ -0,0 +1,8 @@
1
+ import type { Context } from '../context.js';
2
+ export interface ControllerContext {
3
+ ctx: Context;
4
+ }
5
+ export interface Controller<Input, Output> {
6
+ execute(input: Input, context: ControllerContext): Promise<Output> | Output;
7
+ }
8
+ export type TrpcRouterModule = Record<string, unknown>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,60 @@
1
+ import type { ArtifactType, Prisma, PrismaClient } from '@prisma/client';
2
+ import { BaseRepository } from './base.repository.js';
3
+ export declare class ArtifactRepository extends BaseRepository {
4
+ constructor(db: PrismaClient);
5
+ /**
6
+ * Fetch an artifact if the user can access the containing workspace
7
+ * (owner or member).
8
+ */
9
+ findByIdAccessible(artifactId: string, userId: string, include?: Prisma.ArtifactInclude): Prisma.Prisma__ArtifactClient<{
10
+ id: string;
11
+ createdAt: Date;
12
+ updatedAt: Date;
13
+ workspaceId: string;
14
+ type: import("@prisma/client").$Enums.ArtifactType;
15
+ title: string;
16
+ isArchived: boolean;
17
+ difficulty: import("@prisma/client").$Enums.Difficulty | null;
18
+ estimatedTime: string | null;
19
+ createdById: string | null;
20
+ description: string | null;
21
+ generating: boolean;
22
+ generatingMetadata: Prisma.JsonValue | null;
23
+ worksheetConfig: Prisma.JsonValue | null;
24
+ imageObjectKey: string | null;
25
+ } | null, null, import("@prisma/client/runtime/library").DefaultArgs, Prisma.PrismaClientOptions>;
26
+ findByIdAndTypeAccessible(artifactId: string, type: ArtifactType, userId: string, include?: Prisma.ArtifactInclude): Prisma.Prisma__ArtifactClient<{
27
+ id: string;
28
+ createdAt: Date;
29
+ updatedAt: Date;
30
+ workspaceId: string;
31
+ type: import("@prisma/client").$Enums.ArtifactType;
32
+ title: string;
33
+ isArchived: boolean;
34
+ difficulty: import("@prisma/client").$Enums.Difficulty | null;
35
+ estimatedTime: string | null;
36
+ createdById: string | null;
37
+ description: string | null;
38
+ generating: boolean;
39
+ generatingMetadata: Prisma.JsonValue | null;
40
+ worksheetConfig: Prisma.JsonValue | null;
41
+ imageObjectKey: string | null;
42
+ } | null, null, import("@prisma/client/runtime/library").DefaultArgs, Prisma.PrismaClientOptions>;
43
+ listByWorkspaceAndType(workspaceId: string, type: ArtifactType, userId: string, args?: Omit<Prisma.ArtifactFindManyArgs, 'where'>): Prisma.PrismaPromise<{
44
+ id: string;
45
+ createdAt: Date;
46
+ updatedAt: Date;
47
+ workspaceId: string;
48
+ type: import("@prisma/client").$Enums.ArtifactType;
49
+ title: string;
50
+ isArchived: boolean;
51
+ difficulty: import("@prisma/client").$Enums.Difficulty | null;
52
+ estimatedTime: string | null;
53
+ createdById: string | null;
54
+ description: string | null;
55
+ generating: boolean;
56
+ generatingMetadata: Prisma.JsonValue | null;
57
+ worksheetConfig: Prisma.JsonValue | null;
58
+ imageObjectKey: string | null;
59
+ }[]>;
60
+ }
@@ -0,0 +1,40 @@
1
+ import { BaseRepository } from './base.repository.js';
2
+ import { workspaceAccessWhere } from './workspace.repository.js';
3
+ export class ArtifactRepository extends BaseRepository {
4
+ constructor(db) {
5
+ super(db);
6
+ }
7
+ /**
8
+ * Fetch an artifact if the user can access the containing workspace
9
+ * (owner or member).
10
+ */
11
+ findByIdAccessible(artifactId, userId, include) {
12
+ return this.db.artifact.findFirst({
13
+ where: {
14
+ id: artifactId,
15
+ workspace: workspaceAccessWhere(userId),
16
+ },
17
+ include,
18
+ });
19
+ }
20
+ findByIdAndTypeAccessible(artifactId, type, userId, include) {
21
+ return this.db.artifact.findFirst({
22
+ where: {
23
+ id: artifactId,
24
+ type,
25
+ workspace: workspaceAccessWhere(userId),
26
+ },
27
+ include,
28
+ });
29
+ }
30
+ listByWorkspaceAndType(workspaceId, type, userId, args) {
31
+ return this.db.artifact.findMany({
32
+ ...args,
33
+ where: {
34
+ workspaceId,
35
+ type,
36
+ workspace: workspaceAccessWhere(userId),
37
+ },
38
+ });
39
+ }
40
+ }
@@ -0,0 +1,14 @@
1
+ import type { PrismaClient } from '@prisma/client';
2
+ import { logger } from '../lib/logger.js';
3
+ /**
4
+ * Shared base class for repositories.
5
+ *
6
+ * Repositories own data access. They wrap a Prisma client and expose
7
+ * intent-revealing methods (e.g. `findAccessibleById(workspaceId, userId)`)
8
+ * so that the shape of `where` clauses doesn't leak into services/routers.
9
+ */
10
+ export declare abstract class BaseRepository {
11
+ protected readonly db: PrismaClient;
12
+ protected readonly logger: typeof logger;
13
+ constructor(db: PrismaClient);
14
+ }
@@ -0,0 +1,14 @@
1
+ import { logger } from '../lib/logger.js';
2
+ /**
3
+ * Shared base class for repositories.
4
+ *
5
+ * Repositories own data access. They wrap a Prisma client and expose
6
+ * intent-revealing methods (e.g. `findAccessibleById(workspaceId, userId)`)
7
+ * so that the shape of `where` clauses doesn't leak into services/routers.
8
+ */
9
+ export class BaseRepository {
10
+ constructor(db) {
11
+ this.db = db;
12
+ this.logger = logger;
13
+ }
14
+ }
@@ -0,0 +1,94 @@
1
+ import type { Prisma, PrismaClient } from '@prisma/client';
2
+ import { BaseRepository } from './base.repository.js';
3
+ /**
4
+ * Data access for `WorkspaceInvitation`. Members router currently performs
5
+ * invitation CRUD + token validation directly against Prisma — this
6
+ * repository is the target of that extraction during Phase 4.
7
+ */
8
+ export declare class InvitationRepository extends BaseRepository {
9
+ constructor(db: PrismaClient);
10
+ findById(id: string, include?: Prisma.WorkspaceInvitationInclude): Prisma.Prisma__WorkspaceInvitationClient<{
11
+ id: string;
12
+ email: string;
13
+ createdAt: Date;
14
+ updatedAt: Date;
15
+ workspaceId: string;
16
+ role: string;
17
+ token: string;
18
+ invitedById: string;
19
+ acceptedAt: Date | null;
20
+ expiresAt: Date;
21
+ } | null, null, import("@prisma/client/runtime/library").DefaultArgs, Prisma.PrismaClientOptions>;
22
+ findFirst(args: Prisma.WorkspaceInvitationFindFirstArgs): Prisma.Prisma__WorkspaceInvitationClient<{
23
+ id: string;
24
+ email: string;
25
+ createdAt: Date;
26
+ updatedAt: Date;
27
+ workspaceId: string;
28
+ role: string;
29
+ token: string;
30
+ invitedById: string;
31
+ acceptedAt: Date | null;
32
+ expiresAt: Date;
33
+ } | null, null, import("@prisma/client/runtime/library").DefaultArgs, Prisma.PrismaClientOptions>;
34
+ listByWorkspace(workspaceId: string, args?: Omit<Prisma.WorkspaceInvitationFindManyArgs, 'where'>): Prisma.PrismaPromise<{
35
+ id: string;
36
+ email: string;
37
+ createdAt: Date;
38
+ updatedAt: Date;
39
+ workspaceId: string;
40
+ role: string;
41
+ token: string;
42
+ invitedById: string;
43
+ acceptedAt: Date | null;
44
+ expiresAt: Date;
45
+ }[]>;
46
+ listForUserEmail(email: string, args?: Omit<Prisma.WorkspaceInvitationFindManyArgs, 'where'>): Prisma.PrismaPromise<{
47
+ id: string;
48
+ email: string;
49
+ createdAt: Date;
50
+ updatedAt: Date;
51
+ workspaceId: string;
52
+ role: string;
53
+ token: string;
54
+ invitedById: string;
55
+ acceptedAt: Date | null;
56
+ expiresAt: Date;
57
+ }[]>;
58
+ create(data: Prisma.WorkspaceInvitationCreateInput): Prisma.Prisma__WorkspaceInvitationClient<{
59
+ id: string;
60
+ email: string;
61
+ createdAt: Date;
62
+ updatedAt: Date;
63
+ workspaceId: string;
64
+ role: string;
65
+ token: string;
66
+ invitedById: string;
67
+ acceptedAt: Date | null;
68
+ expiresAt: Date;
69
+ }, never, import("@prisma/client/runtime/library").DefaultArgs, Prisma.PrismaClientOptions>;
70
+ update(id: string, data: Prisma.WorkspaceInvitationUpdateInput): Prisma.Prisma__WorkspaceInvitationClient<{
71
+ id: string;
72
+ email: string;
73
+ createdAt: Date;
74
+ updatedAt: Date;
75
+ workspaceId: string;
76
+ role: string;
77
+ token: string;
78
+ invitedById: string;
79
+ acceptedAt: Date | null;
80
+ expiresAt: Date;
81
+ }, never, import("@prisma/client/runtime/library").DefaultArgs, Prisma.PrismaClientOptions>;
82
+ delete(id: string): Prisma.Prisma__WorkspaceInvitationClient<{
83
+ id: string;
84
+ email: string;
85
+ createdAt: Date;
86
+ updatedAt: Date;
87
+ workspaceId: string;
88
+ role: string;
89
+ token: string;
90
+ invitedById: string;
91
+ acceptedAt: Date | null;
92
+ expiresAt: Date;
93
+ }, never, import("@prisma/client/runtime/library").DefaultArgs, Prisma.PrismaClientOptions>;
94
+ }
@@ -0,0 +1,44 @@
1
+ import { BaseRepository } from './base.repository.js';
2
+ /**
3
+ * Data access for `WorkspaceInvitation`. Members router currently performs
4
+ * invitation CRUD + token validation directly against Prisma — this
5
+ * repository is the target of that extraction during Phase 4.
6
+ */
7
+ export class InvitationRepository extends BaseRepository {
8
+ constructor(db) {
9
+ super(db);
10
+ }
11
+ findById(id, include) {
12
+ return this.db.workspaceInvitation.findFirst({
13
+ where: { id },
14
+ include,
15
+ });
16
+ }
17
+ findFirst(args) {
18
+ return this.db.workspaceInvitation.findFirst(args);
19
+ }
20
+ listByWorkspace(workspaceId, args) {
21
+ return this.db.workspaceInvitation.findMany({
22
+ ...args,
23
+ where: { workspaceId },
24
+ });
25
+ }
26
+ listForUserEmail(email, args) {
27
+ return this.db.workspaceInvitation.findMany({
28
+ ...args,
29
+ where: { email },
30
+ });
31
+ }
32
+ create(data) {
33
+ return this.db.workspaceInvitation.create({ data });
34
+ }
35
+ update(id, data) {
36
+ return this.db.workspaceInvitation.update({
37
+ where: { id },
38
+ data,
39
+ });
40
+ }
41
+ delete(id) {
42
+ return this.db.workspaceInvitation.delete({ where: { id } });
43
+ }
44
+ }
@@ -0,0 +1,72 @@
1
+ import type { Prisma, PrismaClient } from '@prisma/client';
2
+ import { BaseRepository } from './base.repository.js';
3
+ /**
4
+ * Thin data-access wrapper around `Notification`. `NotificationService`
5
+ * currently calls `ctx.db.notification.*` directly; Phase 4 will migrate it
6
+ * to use this repository so services don't need Prisma-specific types at
7
+ * their API boundary.
8
+ */
9
+ export declare class NotificationRepository extends BaseRepository {
10
+ constructor(db: PrismaClient);
11
+ findFirst(args: Prisma.NotificationFindFirstArgs): Prisma.Prisma__NotificationClient<{
12
+ id: string;
13
+ createdAt: Date;
14
+ updatedAt: Date;
15
+ workspaceId: string | null;
16
+ type: string;
17
+ title: string;
18
+ content: string | null;
19
+ userId: string;
20
+ actorUserId: string | null;
21
+ body: string;
22
+ actionUrl: string | null;
23
+ metadata: Prisma.JsonValue | null;
24
+ priority: import("@prisma/client").$Enums.NotificationPriority;
25
+ sourceId: string | null;
26
+ read: boolean;
27
+ readAt: Date | null;
28
+ deliveredAt: Date | null;
29
+ } | null, null, import("@prisma/client/runtime/library").DefaultArgs, Prisma.PrismaClientOptions>;
30
+ listByUser(userId: string, args?: Omit<Prisma.NotificationFindManyArgs, 'where'>): Prisma.PrismaPromise<{
31
+ id: string;
32
+ createdAt: Date;
33
+ updatedAt: Date;
34
+ workspaceId: string | null;
35
+ type: string;
36
+ title: string;
37
+ content: string | null;
38
+ userId: string;
39
+ actorUserId: string | null;
40
+ body: string;
41
+ actionUrl: string | null;
42
+ metadata: Prisma.JsonValue | null;
43
+ priority: import("@prisma/client").$Enums.NotificationPriority;
44
+ sourceId: string | null;
45
+ read: boolean;
46
+ readAt: Date | null;
47
+ deliveredAt: Date | null;
48
+ }[]>;
49
+ count(args: Prisma.NotificationCountArgs): Prisma.PrismaPromise<number>;
50
+ create(data: Prisma.NotificationCreateInput): Prisma.Prisma__NotificationClient<{
51
+ id: string;
52
+ createdAt: Date;
53
+ updatedAt: Date;
54
+ workspaceId: string | null;
55
+ type: string;
56
+ title: string;
57
+ content: string | null;
58
+ userId: string;
59
+ actorUserId: string | null;
60
+ body: string;
61
+ actionUrl: string | null;
62
+ metadata: Prisma.JsonValue | null;
63
+ priority: import("@prisma/client").$Enums.NotificationPriority;
64
+ sourceId: string | null;
65
+ read: boolean;
66
+ readAt: Date | null;
67
+ deliveredAt: Date | null;
68
+ }, never, import("@prisma/client/runtime/library").DefaultArgs, Prisma.PrismaClientOptions>;
69
+ markRead(id: string, userId: string): Prisma.PrismaPromise<Prisma.BatchPayload>;
70
+ markAllRead(userId: string): Prisma.PrismaPromise<Prisma.BatchPayload>;
71
+ delete(id: string, userId: string): Prisma.PrismaPromise<Prisma.BatchPayload>;
72
+ }
@@ -0,0 +1,44 @@
1
+ import { BaseRepository } from './base.repository.js';
2
+ /**
3
+ * Thin data-access wrapper around `Notification`. `NotificationService`
4
+ * currently calls `ctx.db.notification.*` directly; Phase 4 will migrate it
5
+ * to use this repository so services don't need Prisma-specific types at
6
+ * their API boundary.
7
+ */
8
+ export class NotificationRepository extends BaseRepository {
9
+ constructor(db) {
10
+ super(db);
11
+ }
12
+ findFirst(args) {
13
+ return this.db.notification.findFirst(args);
14
+ }
15
+ listByUser(userId, args) {
16
+ return this.db.notification.findMany({
17
+ ...args,
18
+ where: { userId },
19
+ });
20
+ }
21
+ count(args) {
22
+ return this.db.notification.count(args);
23
+ }
24
+ create(data) {
25
+ return this.db.notification.create({ data });
26
+ }
27
+ markRead(id, userId) {
28
+ return this.db.notification.updateMany({
29
+ where: { id, userId },
30
+ data: { read: true },
31
+ });
32
+ }
33
+ markAllRead(userId) {
34
+ return this.db.notification.updateMany({
35
+ where: { userId, read: false },
36
+ data: { read: true },
37
+ });
38
+ }
39
+ delete(id, userId) {
40
+ return this.db.notification.deleteMany({
41
+ where: { id, userId },
42
+ });
43
+ }
44
+ }
@@ -0,0 +1,10 @@
1
+ import { BaseRepository } from './base.repository.js';
2
+ /**
3
+ * Adapter repository for legacy router modules during MVC migration.
4
+ * Keeps the transport contract stable while moving ownership boundaries.
5
+ */
6
+ export declare class RouterModuleRepository<TModule> extends BaseRepository {
7
+ private readonly module;
8
+ constructor(db: ConstructorParameters<typeof BaseRepository>[0], module: TModule);
9
+ getModule(): TModule;
10
+ }
@@ -0,0 +1,14 @@
1
+ import { BaseRepository } from './base.repository.js';
2
+ /**
3
+ * Adapter repository for legacy router modules during MVC migration.
4
+ * Keeps the transport contract stable while moving ownership boundaries.
5
+ */
6
+ export class RouterModuleRepository extends BaseRepository {
7
+ constructor(db, module) {
8
+ super(db);
9
+ this.module = module;
10
+ }
11
+ getModule() {
12
+ return this.module;
13
+ }
14
+ }
@@ -0,0 +1,74 @@
1
+ import type { Prisma, PrismaClient } from '@prisma/client';
2
+ import { BaseRepository } from './base.repository.js';
3
+ export declare class UserRepository extends BaseRepository {
4
+ constructor(db: PrismaClient);
5
+ findById(id: string, args?: Omit<Prisma.UserFindUniqueArgs, 'where'>): Prisma.Prisma__UserClient<{
6
+ name: string | null;
7
+ id: string;
8
+ email: string | null;
9
+ emailVerified: Date | null;
10
+ passwordHash: string | null;
11
+ createdAt: Date;
12
+ updatedAt: Date;
13
+ fileAssetId: string | null;
14
+ roleId: string | null;
15
+ deletedAt: Date | null;
16
+ stripe_customer_id: string | null;
17
+ } | null, null, import("@prisma/client/runtime/library").DefaultArgs, Prisma.PrismaClientOptions>;
18
+ findByEmail(email: string, args?: Omit<Prisma.UserFindUniqueArgs, 'where'>): Prisma.Prisma__UserClient<{
19
+ name: string | null;
20
+ id: string;
21
+ email: string | null;
22
+ emailVerified: Date | null;
23
+ passwordHash: string | null;
24
+ createdAt: Date;
25
+ updatedAt: Date;
26
+ fileAssetId: string | null;
27
+ roleId: string | null;
28
+ deletedAt: Date | null;
29
+ stripe_customer_id: string | null;
30
+ } | null, null, import("@prisma/client/runtime/library").DefaultArgs, Prisma.PrismaClientOptions>;
31
+ create(data: Prisma.UserCreateInput): Prisma.Prisma__UserClient<{
32
+ name: string | null;
33
+ id: string;
34
+ email: string | null;
35
+ emailVerified: Date | null;
36
+ passwordHash: string | null;
37
+ createdAt: Date;
38
+ updatedAt: Date;
39
+ fileAssetId: string | null;
40
+ roleId: string | null;
41
+ deletedAt: Date | null;
42
+ stripe_customer_id: string | null;
43
+ }, never, import("@prisma/client/runtime/library").DefaultArgs, Prisma.PrismaClientOptions>;
44
+ update(id: string, data: Prisma.UserUpdateInput): Prisma.Prisma__UserClient<{
45
+ name: string | null;
46
+ id: string;
47
+ email: string | null;
48
+ emailVerified: Date | null;
49
+ passwordHash: string | null;
50
+ createdAt: Date;
51
+ updatedAt: Date;
52
+ fileAssetId: string | null;
53
+ roleId: string | null;
54
+ deletedAt: Date | null;
55
+ stripe_customer_id: string | null;
56
+ }, never, import("@prisma/client/runtime/library").DefaultArgs, Prisma.PrismaClientOptions>;
57
+ /**
58
+ * Soft-delete marker: set `deletedAt`. Hard-delete happens in
59
+ * `scripts/purge-deleted-users.ts`.
60
+ */
61
+ softDelete(id: string): Prisma.Prisma__UserClient<{
62
+ name: string | null;
63
+ id: string;
64
+ email: string | null;
65
+ emailVerified: Date | null;
66
+ passwordHash: string | null;
67
+ createdAt: Date;
68
+ updatedAt: Date;
69
+ fileAssetId: string | null;
70
+ roleId: string | null;
71
+ deletedAt: Date | null;
72
+ stripe_customer_id: string | null;
73
+ }, never, import("@prisma/client/runtime/library").DefaultArgs, Prisma.PrismaClientOptions>;
74
+ }