@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.
- package/.env.example +12 -0
- package/.vscode/settings.json +3 -0
- package/REFACTOR_NOTES.md +60 -0
- package/TESTING_PROMPT.md +225 -0
- package/dist/controllers/admin.controller.d.ts +715 -0
- package/dist/controllers/admin.controller.js +9 -0
- package/dist/controllers/annotations.controller.d.ts +439 -0
- package/dist/controllers/annotations.controller.js +9 -0
- package/dist/controllers/app-router.controller.d.ts +3011 -0
- package/dist/controllers/app-router.controller.js +38 -0
- package/dist/controllers/app-router.controller.test.d.ts +1 -0
- package/dist/controllers/app-router.controller.test.js +36 -0
- package/dist/controllers/auth.controller.d.ts +323 -0
- package/dist/controllers/auth.controller.js +9 -0
- package/dist/controllers/base.controller.d.ts +4 -0
- package/dist/controllers/base.controller.js +5 -0
- package/dist/controllers/chat.controller.d.ts +341 -0
- package/dist/controllers/chat.controller.js +9 -0
- package/dist/controllers/copilot.controller.d.ts +397 -0
- package/dist/controllers/copilot.controller.js +9 -0
- package/dist/controllers/flashcards.controller.d.ts +651 -0
- package/dist/controllers/flashcards.controller.js +9 -0
- package/dist/controllers/members.controller.d.ts +339 -0
- package/dist/controllers/members.controller.js +9 -0
- package/dist/controllers/notifications.controller.d.ts +199 -0
- package/dist/controllers/notifications.controller.js +9 -0
- package/dist/controllers/payment.controller.d.ts +181 -0
- package/dist/controllers/payment.controller.js +9 -0
- package/dist/controllers/podcast.controller.d.ts +575 -0
- package/dist/controllers/podcast.controller.js +9 -0
- package/dist/controllers/router-module.controller.d.ts +5 -0
- package/dist/controllers/router-module.controller.js +6 -0
- package/dist/controllers/studyguide.controller.d.ts +73 -0
- package/dist/controllers/studyguide.controller.js +9 -0
- package/dist/controllers/worksheets.controller.d.ts +829 -0
- package/dist/controllers/worksheets.controller.js +9 -0
- package/dist/controllers/workspace.controller.d.ts +1207 -0
- package/dist/controllers/workspace.controller.js +9 -0
- package/dist/lib/activity_human_description.test.js +16 -15
- package/dist/lib/activity_log_service.test.js +28 -23
- package/dist/lib/ai/config.d.ts +20 -0
- package/dist/lib/ai/config.js +31 -0
- package/dist/lib/ai/embedding-client.d.ts +8 -0
- package/dist/lib/ai/embedding-client.js +30 -0
- package/dist/lib/ai/index.d.ts +47 -0
- package/dist/lib/ai/index.js +28 -0
- package/dist/lib/ai/inference-backend/client.d.ts +28 -0
- package/dist/lib/ai/inference-backend/client.js +301 -0
- package/dist/lib/ai/inference-backend/mocks.d.ts +12 -0
- package/dist/lib/ai/inference-backend/mocks.js +133 -0
- package/dist/lib/ai/inference-backend/types.d.ts +44 -0
- package/dist/lib/ai/inference-backend/types.js +1 -0
- package/dist/lib/ai/json-parse.d.ts +2 -0
- package/dist/lib/ai/json-parse.js +34 -0
- package/dist/lib/ai/llm-client.d.ts +6 -0
- package/dist/lib/ai/llm-client.js +19 -0
- package/dist/lib/ai/mock.d.ts +2 -0
- package/dist/lib/ai/mock.js +10 -0
- package/dist/lib/ai/types.d.ts +9 -0
- package/dist/lib/ai/types.js +1 -0
- package/dist/lib/chunking.d.ts +19 -0
- package/dist/lib/chunking.js +47 -0
- package/dist/lib/curated-kb-seed.d.ts +12 -0
- package/dist/lib/curated-kb-seed.js +155 -0
- package/dist/lib/email.js +67 -108
- package/dist/lib/embeddings.d.ts +2 -0
- package/dist/lib/embeddings.js +1 -0
- package/dist/lib/ensure-curated-kb-catalog.d.ts +6 -0
- package/dist/lib/ensure-curated-kb-catalog.js +53 -0
- package/dist/lib/env.d.ts +1 -5
- package/dist/lib/env.js +2 -7
- package/dist/lib/inference.d.ts +1 -8
- package/dist/lib/inference.js +1 -19
- package/dist/lib/kb-meta.d.ts +8 -0
- package/dist/lib/kb-meta.js +77 -0
- package/dist/lib/note-text.d.ts +1 -0
- package/dist/lib/note-text.js +47 -0
- package/dist/lib/notification-service.test.js +37 -36
- package/dist/lib/pdf.d.ts +11 -0
- package/dist/lib/pdf.js +11 -0
- package/dist/lib/usage_service.d.ts +2 -1
- package/dist/lib/usage_service.js +30 -12
- package/dist/lib/worksheet-generation.js +4 -4
- package/dist/lib/worksheet-generation.test.js +32 -17
- package/dist/lib/workspace-kb.d.ts +5 -0
- package/dist/lib/workspace-kb.js +7 -0
- package/dist/models/controller-context.model.d.ts +8 -0
- package/dist/models/controller-context.model.js +1 -0
- package/dist/repositories/artifact.repository.d.ts +60 -0
- package/dist/repositories/artifact.repository.js +40 -0
- package/dist/repositories/base.repository.d.ts +14 -0
- package/dist/repositories/base.repository.js +14 -0
- package/dist/repositories/invitation.repository.d.ts +94 -0
- package/dist/repositories/invitation.repository.js +44 -0
- package/dist/repositories/notification.repository.d.ts +72 -0
- package/dist/repositories/notification.repository.js +44 -0
- package/dist/repositories/router-module.repository.d.ts +10 -0
- package/dist/repositories/router-module.repository.js +14 -0
- package/dist/repositories/user.repository.d.ts +74 -0
- package/dist/repositories/user.repository.js +37 -0
- package/dist/repositories/workspace-member.repository.d.ts +31 -0
- package/dist/repositories/workspace-member.repository.js +31 -0
- package/dist/repositories/workspace.repository.d.ts +97 -0
- package/dist/repositories/workspace.repository.js +79 -0
- package/dist/routers/_app.d.ts +528 -33
- package/dist/routers/_app.js +4 -0
- package/dist/routers/admin.d.ts +0 -4
- package/dist/routers/admin.js +21 -549
- package/dist/routers/annotations.js +12 -170
- package/dist/routers/artifactVersions.d.ts +65 -0
- package/dist/routers/artifactVersions.js +14 -0
- package/dist/routers/auth.d.ts +0 -6
- package/dist/routers/auth.js +36 -421
- package/dist/routers/chat.js +15 -229
- package/dist/routers/copilot.d.ts +14 -13
- package/dist/routers/copilot.js +13 -532
- package/dist/routers/flashcards.d.ts +5 -5
- package/dist/routers/flashcards.js +23 -349
- package/dist/routers/knowledgeBase.d.ts +421 -0
- package/dist/routers/knowledgeBase.js +118 -0
- package/dist/routers/members.d.ts +0 -41
- package/dist/routers/members.js +22 -710
- package/dist/routers/notes.d.ts +94 -0
- package/dist/routers/notes.js +37 -0
- package/dist/routers/notifications.js +7 -109
- package/dist/routers/payment.d.ts +3 -2
- package/dist/routers/payment.js +11 -393
- package/dist/routers/podcast.d.ts +1 -1
- package/dist/routers/podcast.js +11 -784
- package/dist/routers/studyguide.js +3 -129
- package/dist/routers/worksheets.d.ts +29 -14
- package/dist/routers/worksheets.js +49 -628
- package/dist/routers/workspace.d.ts +0 -4
- package/dist/routers/workspace.js +28 -922
- package/dist/scripts/purge-deleted-users.js +2 -2
- package/dist/server.js +10 -3
- package/dist/services/activity/activity-human-description.service.d.ts +13 -0
- package/dist/services/activity/activity-human-description.service.js +221 -0
- package/dist/services/activity/activity-human-description.service.test.d.ts +1 -0
- package/dist/services/activity/activity-human-description.service.test.js +16 -0
- package/dist/services/activity/activity-log.service.d.ts +87 -0
- package/dist/services/activity/activity-log.service.js +276 -0
- package/dist/services/activity/activity-log.service.test.d.ts +1 -0
- package/dist/services/activity/activity-log.service.test.js +27 -0
- package/dist/services/activity-human-description.service.d.ts +13 -0
- package/dist/services/activity-human-description.service.js +221 -0
- package/dist/services/activity-human-description.service.test.d.ts +1 -0
- package/dist/services/activity-human-description.service.test.js +16 -0
- package/dist/services/activity-log.service.d.ts +87 -0
- package/dist/services/activity-log.service.js +276 -0
- package/dist/services/activity-log.service.test.d.ts +1 -0
- package/dist/services/activity-log.service.test.js +27 -0
- package/dist/services/admin/admin.service.d.ts +270 -0
- package/dist/services/admin/admin.service.js +476 -0
- package/dist/services/admin.service.d.ts +270 -0
- package/dist/services/admin.service.js +476 -0
- package/dist/services/ai/ai-session.service.d.ts +5 -0
- package/dist/services/ai/ai-session.service.js +4 -0
- package/dist/services/ai-session.service.d.ts +60 -0
- package/dist/services/ai-session.service.js +561 -0
- package/dist/services/annotation.service.d.ts +177 -0
- package/dist/services/annotation.service.js +154 -0
- package/dist/services/artifact-notification.service.d.ts +14 -0
- package/dist/services/artifact-notification.service.js +20 -0
- package/dist/services/artifact-version.service.d.ts +38 -0
- package/dist/services/artifact-version.service.js +129 -0
- package/dist/services/artifacts/annotation.service.d.ts +177 -0
- package/dist/services/artifacts/annotation.service.js +154 -0
- package/dist/services/artifacts/artifact-version.service.d.ts +38 -0
- package/dist/services/artifacts/artifact-version.service.js +129 -0
- package/dist/services/artifacts/chat.service.d.ts +127 -0
- package/dist/services/artifacts/chat.service.js +182 -0
- package/dist/services/artifacts/study-guide.service.d.ts +18 -0
- package/dist/services/artifacts/study-guide.service.js +65 -0
- package/dist/services/auth/auth.service.d.ts +94 -0
- package/dist/services/auth/auth.service.js +368 -0
- package/dist/services/auth.service.d.ts +94 -0
- package/dist/services/auth.service.js +368 -0
- package/dist/services/base.service.d.ts +14 -0
- package/dist/services/base.service.js +14 -0
- package/dist/services/billing/payment.service.d.ts +55 -0
- package/dist/services/billing/payment.service.js +368 -0
- package/dist/services/billing/subscription.service.d.ts +37 -0
- package/dist/services/billing/subscription.service.js +654 -0
- package/dist/services/billing/usage.service.d.ts +27 -0
- package/dist/services/billing/usage.service.js +77 -0
- package/dist/services/chat.service.d.ts +127 -0
- package/dist/services/chat.service.js +182 -0
- package/dist/services/content/copilot.service.d.ts +113 -0
- package/dist/services/content/copilot.service.js +453 -0
- package/dist/services/content/flashcard-progress.service.d.ts +159 -0
- package/dist/services/content/flashcard-progress.service.js +432 -0
- package/dist/services/content/flashcard.service.d.ts +140 -0
- package/dist/services/content/flashcard.service.js +326 -0
- package/dist/services/content/media-analysis.service.d.ts +23 -0
- package/dist/services/content/media-analysis.service.js +404 -0
- package/dist/services/content/podcast.service.d.ts +267 -0
- package/dist/services/content/podcast.service.js +653 -0
- package/dist/services/content/worksheet-content.service.d.ts +37 -0
- package/dist/services/content/worksheet-content.service.js +84 -0
- package/dist/services/content/worksheet-content.service.test.d.ts +1 -0
- package/dist/services/content/worksheet-content.service.test.js +69 -0
- package/dist/services/content/worksheet-generation.service.d.ts +91 -0
- package/dist/services/content/worksheet-generation.service.js +95 -0
- package/dist/services/content/worksheet-generation.service.test.d.ts +1 -0
- package/dist/services/content/worksheet-generation.service.test.js +20 -0
- package/dist/services/content/worksheet.service.d.ts +347 -0
- package/dist/services/content/worksheet.service.js +599 -0
- package/dist/services/copilot.service.d.ts +116 -0
- package/dist/services/copilot.service.js +447 -0
- package/dist/services/flashcard-progress.service.d.ts +2 -2
- package/dist/services/flashcard-progress.service.js +3 -2
- package/dist/services/flashcard.service.d.ts +140 -0
- package/dist/services/flashcard.service.js +325 -0
- package/dist/services/invitation.service.d.ts +66 -0
- package/dist/services/invitation.service.js +348 -0
- package/dist/services/knowledge/knowledge-base.service.d.ts +316 -0
- package/dist/services/knowledge/knowledge-base.service.js +544 -0
- package/dist/services/knowledge-base.service.d.ts +316 -0
- package/dist/services/knowledge-base.service.js +536 -0
- package/dist/services/media-analysis.service.d.ts +23 -0
- package/dist/services/media-analysis.service.js +384 -0
- package/dist/services/member.service.d.ts +36 -0
- package/dist/services/member.service.js +193 -0
- package/dist/services/members/invitation.service.d.ts +66 -0
- package/dist/services/members/invitation.service.js +348 -0
- package/dist/services/members/member.service.d.ts +36 -0
- package/dist/services/members/member.service.js +193 -0
- package/dist/services/note.service.d.ts +55 -0
- package/dist/services/note.service.js +111 -0
- package/dist/services/notification.service.d.ts +214 -0
- package/dist/services/notification.service.js +550 -0
- package/dist/services/notification.service.test.d.ts +1 -0
- package/dist/services/notification.service.test.js +87 -0
- package/dist/services/notifications/notification.service.d.ts +214 -0
- package/dist/services/notifications/notification.service.js +550 -0
- package/dist/services/notifications/notification.service.test.d.ts +1 -0
- package/dist/services/notifications/notification.service.test.js +87 -0
- package/dist/services/payment.service.d.ts +55 -0
- package/dist/services/payment.service.js +368 -0
- package/dist/services/podcast.service.d.ts +267 -0
- package/dist/services/podcast.service.js +654 -0
- package/dist/services/router-module.service.d.ts +7 -0
- package/dist/services/router-module.service.js +10 -0
- package/dist/services/study-guide.service.d.ts +18 -0
- package/dist/services/study-guide.service.js +65 -0
- package/dist/services/subscription.service.d.ts +37 -0
- package/dist/services/subscription.service.js +654 -0
- package/dist/services/usage-limit-policy.service.d.ts +12 -0
- package/dist/services/usage-limit-policy.service.js +22 -0
- package/dist/services/usage-limit-policy.service.test.d.ts +1 -0
- package/dist/services/usage-limit-policy.service.test.js +46 -0
- package/dist/services/usage.service.d.ts +27 -0
- package/dist/services/usage.service.js +77 -0
- package/dist/services/worksheet-content.service.d.ts +42 -0
- package/dist/services/worksheet-content.service.js +84 -0
- package/dist/services/worksheet-content.service.test.d.ts +1 -0
- package/dist/services/worksheet-content.service.test.js +69 -0
- package/dist/services/worksheet-generation.service.d.ts +91 -0
- package/dist/services/worksheet-generation.service.js +95 -0
- package/dist/services/worksheet-generation.service.test.d.ts +1 -0
- package/dist/services/worksheet-generation.service.test.js +20 -0
- package/dist/services/worksheet.service.d.ts +385 -0
- package/dist/services/worksheet.service.js +596 -0
- package/dist/services/workspace/workspace-analytics.service.d.ts +24 -0
- package/dist/services/workspace/workspace-analytics.service.js +95 -0
- package/dist/services/workspace/workspace-kb.service.d.ts +40 -0
- package/dist/services/workspace/workspace-kb.service.js +184 -0
- package/dist/services/workspace/workspace.service.d.ts +307 -0
- package/dist/services/workspace/workspace.service.js +394 -0
- package/dist/services/workspace-analytics.service.d.ts +24 -0
- package/dist/services/workspace-analytics.service.js +95 -0
- package/dist/services/workspace-kb.service.d.ts +40 -0
- package/dist/services/workspace-kb.service.js +184 -0
- package/dist/services/workspace-progress.service.d.ts +27 -0
- package/dist/services/workspace-progress.service.js +56 -0
- package/dist/services/workspace-progress.service.test.d.ts +1 -0
- package/dist/services/workspace-progress.service.test.js +49 -0
- package/dist/services/workspace.service.d.ts +307 -0
- package/dist/services/workspace.service.js +390 -0
- package/dist/trpc.js +2 -2
- package/package.json +5 -6
- package/prisma/migrations/20260509000001_add_knowledge_base/migration.sql +99 -0
- package/prisma/migrations/20260509000002_curate_knowledge_base/migration.sql +52 -0
- package/prisma/migrations/20260522000000_add_notes/migration.sql +27 -0
- package/prisma/migrations/20260524000000_remove_notes/migration.sql +3 -0
- package/prisma/schema.prisma +150 -48
- package/prisma/seed.mjs +67 -0
- package/scripts/debug/README.md +4 -0
- package/src/README.md +63 -0
- package/src/lib/ai/config.ts +34 -0
- package/src/lib/ai/embedding-client.ts +47 -0
- package/src/lib/ai/index.ts +62 -0
- package/src/lib/ai/inference-backend/client.ts +479 -0
- package/src/lib/ai/inference-backend/mocks.ts +171 -0
- package/src/lib/ai/inference-backend/types.ts +50 -0
- package/src/lib/ai/json-parse.ts +35 -0
- package/src/lib/ai/llm-client.ts +31 -0
- package/src/lib/ai/mock.ts +12 -0
- package/src/lib/ai/types.ts +11 -0
- package/src/lib/chunking.ts +81 -0
- package/src/lib/curated-kb-seed.ts +164 -0
- package/src/lib/email.ts +77 -115
- package/src/lib/embeddings.ts +9 -0
- package/src/lib/ensure-curated-kb-catalog.ts +60 -0
- package/src/lib/env.ts +2 -7
- package/src/lib/inference.ts +1 -21
- package/src/lib/kb-meta.ts +81 -0
- package/src/lib/pdf.ts +23 -0
- package/src/lib/workspace-kb.ts +7 -0
- package/src/repositories/artifact.repository.ts +55 -0
- package/src/repositories/base.repository.ts +19 -0
- package/src/repositories/invitation.repository.ts +53 -0
- package/src/repositories/notification.repository.ts +53 -0
- package/src/repositories/user.repository.ts +44 -0
- package/src/repositories/workspace-member.repository.ts +38 -0
- package/src/repositories/workspace.repository.ts +89 -0
- package/src/routers/_app.ts +4 -0
- package/src/routers/admin.ts +124 -692
- package/src/routers/annotations.ts +25 -203
- package/src/routers/artifactVersions.ts +32 -0
- package/src/routers/auth.ts +81 -519
- package/src/routers/chat.ts +42 -245
- package/src/routers/copilot.ts +41 -666
- package/src/routers/flashcards.ts +108 -404
- package/src/routers/knowledgeBase.ts +216 -0
- package/src/routers/members.ts +60 -782
- package/src/routers/notifications.ts +15 -117
- package/src/routers/payment.ts +37 -446
- package/src/routers/podcast.ts +36 -898
- package/src/routers/studyguide.ts +5 -144
- package/src/routers/worksheets.ts +171 -735
- package/src/routers/workspace.ts +138 -1109
- package/src/scripts/purge-deleted-users.ts +2 -2
- package/src/server.ts +10 -3
- package/src/{lib/activity_human_description.test.ts → services/activity/activity-human-description.service.test.ts} +1 -1
- package/src/{lib/activity_log_service.test.ts → services/activity/activity-log.service.test.ts} +1 -1
- package/src/{lib/activity_log_service.ts → services/activity/activity-log.service.ts} +2 -2
- package/src/services/admin/admin.service.ts +612 -0
- package/src/services/ai/ai-session.service.ts +5 -0
- package/src/services/artifacts/annotation.service.ts +189 -0
- package/src/services/artifacts/artifact-version.service.ts +151 -0
- package/src/services/artifacts/chat.service.ts +197 -0
- package/src/services/artifacts/study-guide.service.ts +72 -0
- package/src/services/auth/auth.service.ts +473 -0
- package/src/services/base.service.ts +19 -0
- package/src/services/billing/payment.service.ts +436 -0
- package/src/{lib/subscription_service.ts → services/billing/subscription.service.ts} +5 -5
- package/src/{lib/usage_service.ts → services/billing/usage.service.ts} +32 -12
- package/src/services/content/copilot.service.ts +596 -0
- package/src/services/{flashcard-progress.service.ts → content/flashcard-progress.service.ts} +6 -3
- package/src/services/content/flashcard.service.ts +394 -0
- package/src/services/content/media-analysis.service.ts +556 -0
- package/src/services/content/podcast.service.ts +777 -0
- package/src/services/content/worksheet-content.service.test.ts +83 -0
- package/src/services/content/worksheet-content.service.ts +117 -0
- package/src/{lib/worksheet-generation.test.ts → services/content/worksheet-generation.service.test.ts} +1 -1
- package/src/services/content/worksheet.service.ts +751 -0
- package/src/services/knowledge/knowledge-base.service.ts +705 -0
- package/src/services/members/invitation.service.ts +427 -0
- package/src/services/members/member.service.ts +241 -0
- package/src/{lib/notification-service.test.ts → services/notifications/notification.service.test.ts} +2 -2
- package/src/{lib/notification-service.ts → services/notifications/notification.service.ts} +102 -1
- package/src/services/workspace/workspace-analytics.service.ts +107 -0
- package/src/services/workspace/workspace-kb.service.ts +273 -0
- package/src/services/workspace/workspace.service.ts +481 -0
- package/src/trpc.ts +2 -2
- package/src/lib/ai-session.ts +0 -704
- package/src/lib/workspace-access.ts +0 -13
- /package/{check-difficulty.cjs → scripts/debug/check-difficulty.cjs} +0 -0
- /package/{check-questions.cjs → scripts/debug/check-questions.cjs} +0 -0
- /package/{db-summary.cjs → scripts/debug/db-summary.cjs} +0 -0
- /package/{mcq-test.cjs → scripts/debug/mcq-test.cjs} +0 -0
- /package/{test-generate.js → scripts/debug/test-generate.js} +0 -0
- /package/{test-ratio.cjs → scripts/debug/test-ratio.cjs} +0 -0
- /package/{zod-test.cjs → scripts/debug/zod-test.cjs} +0 -0
- /package/src/{lib/activity_human_description.ts → services/activity/activity-human-description.service.ts} +0 -0
- /package/src/{lib/worksheet-generation.ts → services/content/worksheet-generation.service.ts} +0 -0
package/prisma/schema.prisma
CHANGED
|
@@ -65,6 +65,19 @@ enum ActivityLogStatus {
|
|
|
65
65
|
FAILURE
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
enum KnowledgeBaseStatus {
|
|
69
|
+
READY
|
|
70
|
+
INDEXING
|
|
71
|
+
ERROR
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
enum KnowledgeBaseDocumentStatus {
|
|
75
|
+
PENDING
|
|
76
|
+
PROCESSING
|
|
77
|
+
READY
|
|
78
|
+
FAILED
|
|
79
|
+
}
|
|
80
|
+
|
|
68
81
|
//
|
|
69
82
|
// NextAuth-compatible auth models (minimal)
|
|
70
83
|
//
|
|
@@ -106,6 +119,8 @@ model User {
|
|
|
106
119
|
idempotencyRecords IdempotencyRecord[]
|
|
107
120
|
activityLogs ActivityLog[] @relation("ActivityLogActor")
|
|
108
121
|
passwordResetTokens PasswordResetToken[]
|
|
122
|
+
knowledgeBases KnowledgeBase[] @relation("UserKnowledgeBases")
|
|
123
|
+
workspaceKnowledgeBases WorkspaceKnowledgeBase[] @relation("UserWorkspaceKnowledgeBases")
|
|
109
124
|
}
|
|
110
125
|
|
|
111
126
|
/// One-time tokens for forgot-password flow (token stored as SHA-256 hash of the secret from the email link).
|
|
@@ -128,7 +143,7 @@ model Role {
|
|
|
128
143
|
}
|
|
129
144
|
|
|
130
145
|
model Notification {
|
|
131
|
-
id String
|
|
146
|
+
id String @id @default(cuid())
|
|
132
147
|
userId String
|
|
133
148
|
actorUserId String?
|
|
134
149
|
workspaceId String?
|
|
@@ -138,22 +153,22 @@ model Notification {
|
|
|
138
153
|
content String?
|
|
139
154
|
actionUrl String?
|
|
140
155
|
metadata Json?
|
|
141
|
-
priority NotificationPriority
|
|
156
|
+
priority NotificationPriority @default(NORMAL)
|
|
142
157
|
sourceId String?
|
|
143
|
-
read Boolean
|
|
158
|
+
read Boolean @default(false)
|
|
144
159
|
readAt DateTime?
|
|
145
160
|
deliveredAt DateTime?
|
|
146
|
-
createdAt DateTime
|
|
147
|
-
updatedAt DateTime
|
|
148
|
-
user User
|
|
149
|
-
actor User?
|
|
150
|
-
workspace Workspace?
|
|
161
|
+
createdAt DateTime @default(now())
|
|
162
|
+
updatedAt DateTime @updatedAt
|
|
163
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
164
|
+
actor User? @relation("NotificationActor", fields: [actorUserId], references: [id], onDelete: SetNull)
|
|
165
|
+
workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
|
|
151
166
|
|
|
167
|
+
@@unique([userId, type, sourceId])
|
|
152
168
|
@@index([userId, read, createdAt(sort: Desc)])
|
|
153
169
|
@@index([userId, createdAt(sort: Desc)])
|
|
154
170
|
@@index([type, createdAt(sort: Desc)])
|
|
155
171
|
@@index([workspaceId])
|
|
156
|
-
@@unique([userId, type, sourceId])
|
|
157
172
|
}
|
|
158
173
|
|
|
159
174
|
model Session {
|
|
@@ -212,6 +227,7 @@ model Workspace {
|
|
|
212
227
|
invitations WorkspaceInvitation[]
|
|
213
228
|
notifications Notification[]
|
|
214
229
|
activityLogs ActivityLog[]
|
|
230
|
+
knowledgeBases WorkspaceKnowledgeBase[]
|
|
215
231
|
createdAt DateTime @default(now())
|
|
216
232
|
updatedAt DateTime @updatedAt
|
|
217
233
|
|
|
@@ -243,15 +259,15 @@ model Chat {
|
|
|
243
259
|
}
|
|
244
260
|
|
|
245
261
|
model CopilotConversation {
|
|
246
|
-
id String
|
|
262
|
+
id String @id @default(cuid())
|
|
247
263
|
workspaceId String
|
|
248
|
-
workspace Workspace
|
|
264
|
+
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
249
265
|
userId String
|
|
250
|
-
user User
|
|
251
|
-
title String
|
|
266
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
267
|
+
title String @default("New Chat")
|
|
252
268
|
messages CopilotMessage[]
|
|
253
|
-
createdAt DateTime
|
|
254
|
-
updatedAt DateTime
|
|
269
|
+
createdAt DateTime @default(now())
|
|
270
|
+
updatedAt DateTime @updatedAt
|
|
255
271
|
|
|
256
272
|
@@index([workspaceId, userId, updatedAt])
|
|
257
273
|
}
|
|
@@ -440,15 +456,15 @@ model WorksheetQuestionProgress {
|
|
|
440
456
|
}
|
|
441
457
|
|
|
442
458
|
model WorksheetPreset {
|
|
443
|
-
id String
|
|
459
|
+
id String @id @default(cuid())
|
|
444
460
|
userId String?
|
|
445
461
|
workspaceId String?
|
|
446
462
|
name String
|
|
447
|
-
isSystem Boolean
|
|
463
|
+
isSystem Boolean @default(false)
|
|
448
464
|
config Json
|
|
449
|
-
createdAt DateTime
|
|
450
|
-
updatedAt DateTime
|
|
451
|
-
user User?
|
|
465
|
+
createdAt DateTime @default(now())
|
|
466
|
+
updatedAt DateTime @updatedAt
|
|
467
|
+
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
452
468
|
workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
453
469
|
|
|
454
470
|
@@index([userId, workspaceId])
|
|
@@ -512,18 +528,18 @@ model PodcastSegment {
|
|
|
512
528
|
}
|
|
513
529
|
|
|
514
530
|
model Invoice {
|
|
515
|
-
id String
|
|
531
|
+
id String @id @default(cuid())
|
|
516
532
|
userId String
|
|
517
533
|
subscriptionId String?
|
|
518
|
-
stripeInvoiceId String
|
|
534
|
+
stripeInvoiceId String @unique
|
|
519
535
|
amountPaid Int
|
|
520
536
|
status String
|
|
521
537
|
invoicePdfUrl String?
|
|
522
538
|
hostedInvoiceUrl String?
|
|
523
539
|
paidAt DateTime?
|
|
524
|
-
type InvoiceType
|
|
525
|
-
createdAt DateTime
|
|
526
|
-
user User
|
|
540
|
+
type InvoiceType @default(SUBSCRIPTION)
|
|
541
|
+
createdAt DateTime @default(now())
|
|
542
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
527
543
|
subscription Subscription? @relation(fields: [subscriptionId], references: [id])
|
|
528
544
|
|
|
529
545
|
@@index([userId])
|
|
@@ -596,48 +612,48 @@ model UserCredit {
|
|
|
596
612
|
}
|
|
597
613
|
|
|
598
614
|
model IdempotencyRecord {
|
|
599
|
-
id
|
|
600
|
-
userId
|
|
601
|
-
planId
|
|
602
|
-
resourceType
|
|
603
|
-
stripeSessionId
|
|
604
|
-
status
|
|
605
|
-
activeLockKey
|
|
606
|
-
|
|
607
|
-
createdAt
|
|
608
|
-
updatedAt
|
|
609
|
-
user
|
|
615
|
+
id String @id @default(cuid())
|
|
616
|
+
userId String
|
|
617
|
+
planId String? // The plan being purchased
|
|
618
|
+
resourceType ArtifactType? // The resource for top-ups
|
|
619
|
+
stripeSessionId String? // The Stripe Checkout Session ID
|
|
620
|
+
status String @default("pending") // pending, completed, failed, expired
|
|
621
|
+
activeLockKey String? @unique // Unique lock: "user_id_plan_id" (Nullified when done)
|
|
622
|
+
|
|
623
|
+
createdAt DateTime @default(now())
|
|
624
|
+
updatedAt DateTime @updatedAt
|
|
625
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
610
626
|
|
|
611
627
|
@@index([userId, status])
|
|
612
628
|
@@index([activeLockKey])
|
|
613
629
|
}
|
|
614
630
|
|
|
615
631
|
model StripeEvent {
|
|
616
|
-
id
|
|
617
|
-
stripeEventId
|
|
618
|
-
type
|
|
619
|
-
status
|
|
620
|
-
error
|
|
621
|
-
processedAt
|
|
622
|
-
createdAt
|
|
623
|
-
updatedAt
|
|
632
|
+
id String @id @default(cuid())
|
|
633
|
+
stripeEventId String @unique // Stripe event ID (e.g. evt_...)
|
|
634
|
+
type String // Event type (e.g. checkout.session.completed)
|
|
635
|
+
status String @default("pending") // pending, processed, failed
|
|
636
|
+
error String? // Error message if processing fails
|
|
637
|
+
processedAt DateTime?
|
|
638
|
+
createdAt DateTime @default(now())
|
|
639
|
+
updatedAt DateTime @updatedAt
|
|
624
640
|
|
|
625
641
|
@@index([stripeEventId])
|
|
626
642
|
}
|
|
627
643
|
|
|
628
644
|
/// Append-only system / user activity (tRPC and explicit events). Retention via admin or scheduled job.
|
|
629
645
|
model ActivityLog {
|
|
630
|
-
id String
|
|
631
|
-
createdAt DateTime
|
|
646
|
+
id String @id @default(cuid())
|
|
647
|
+
createdAt DateTime @default(now())
|
|
632
648
|
actorUserId String?
|
|
633
|
-
actor User?
|
|
649
|
+
actor User? @relation("ActivityLogActor", fields: [actorUserId], references: [id], onDelete: SetNull)
|
|
634
650
|
actorEmailSnapshot String?
|
|
635
651
|
action String
|
|
636
652
|
category ActivityLogCategory
|
|
637
653
|
resourceType String?
|
|
638
654
|
resourceId String?
|
|
639
655
|
workspaceId String?
|
|
640
|
-
workspace Workspace?
|
|
656
|
+
workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
|
|
641
657
|
trpcPath String?
|
|
642
658
|
httpMethod String?
|
|
643
659
|
status ActivityLogStatus
|
|
@@ -653,3 +669,89 @@ model ActivityLog {
|
|
|
653
669
|
@@index([category, createdAt(sort: Desc)])
|
|
654
670
|
}
|
|
655
671
|
|
|
672
|
+
/// A retrieval-augmented knowledge base. Knowledge bases live in a global
|
|
673
|
+
/// catalog managed by System Admins; workspaces opt-in by attaching one
|
|
674
|
+
/// (see `WorkspaceKnowledgeBase`). When `isCurated = true` the KB shows up
|
|
675
|
+
/// in the user-facing catalog search so any workspace can add it.
|
|
676
|
+
///
|
|
677
|
+
/// Each knowledge base owns uploaded documents (PDFs, etc.) which are split
|
|
678
|
+
/// into chunks with pgvector embeddings for semantic search.
|
|
679
|
+
model KnowledgeBase {
|
|
680
|
+
id String @id @default(cuid())
|
|
681
|
+
createdById String?
|
|
682
|
+
createdBy User? @relation("UserKnowledgeBases", fields: [createdById], references: [id], onDelete: SetNull)
|
|
683
|
+
name String
|
|
684
|
+
description String?
|
|
685
|
+
isCurated Boolean @default(false)
|
|
686
|
+
status KnowledgeBaseStatus @default(READY)
|
|
687
|
+
embeddingModel String @default("text-embedding-3-small")
|
|
688
|
+
embeddingDim Int @default(1536)
|
|
689
|
+
meta Json?
|
|
690
|
+
documents KnowledgeBaseDocument[]
|
|
691
|
+
workspaces WorkspaceKnowledgeBase[]
|
|
692
|
+
createdAt DateTime @default(now())
|
|
693
|
+
updatedAt DateTime @updatedAt
|
|
694
|
+
|
|
695
|
+
@@index([isCurated, updatedAt(sort: Desc)])
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/// Many-to-many join between Workspace and KnowledgeBase. A row exists
|
|
699
|
+
/// whenever a workspace has "added" a knowledge base from the catalog (or
|
|
700
|
+
/// when an admin attaches one directly).
|
|
701
|
+
model WorkspaceKnowledgeBase {
|
|
702
|
+
id String @id @default(cuid())
|
|
703
|
+
workspaceId String
|
|
704
|
+
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
|
705
|
+
knowledgeBaseId String
|
|
706
|
+
knowledgeBase KnowledgeBase @relation(fields: [knowledgeBaseId], references: [id], onDelete: Cascade)
|
|
707
|
+
addedById String?
|
|
708
|
+
addedBy User? @relation("UserWorkspaceKnowledgeBases", fields: [addedById], references: [id], onDelete: SetNull)
|
|
709
|
+
createdAt DateTime @default(now())
|
|
710
|
+
|
|
711
|
+
@@unique([workspaceId, knowledgeBaseId])
|
|
712
|
+
@@index([workspaceId])
|
|
713
|
+
@@index([knowledgeBaseId])
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/// A single uploaded source document inside a knowledge base.
|
|
717
|
+
model KnowledgeBaseDocument {
|
|
718
|
+
id String @id @default(cuid())
|
|
719
|
+
knowledgeBaseId String
|
|
720
|
+
knowledgeBase KnowledgeBase @relation(fields: [knowledgeBaseId], references: [id], onDelete: Cascade)
|
|
721
|
+
name String
|
|
722
|
+
mimeType String
|
|
723
|
+
size Int
|
|
724
|
+
bucket String?
|
|
725
|
+
objectKey String?
|
|
726
|
+
status KnowledgeBaseDocumentStatus @default(PENDING)
|
|
727
|
+
errorMessage String?
|
|
728
|
+
numChunks Int @default(0)
|
|
729
|
+
numPages Int?
|
|
730
|
+
meta Json?
|
|
731
|
+
chunks KnowledgeBaseChunk[]
|
|
732
|
+
createdAt DateTime @default(now())
|
|
733
|
+
updatedAt DateTime @updatedAt
|
|
734
|
+
|
|
735
|
+
@@index([knowledgeBaseId])
|
|
736
|
+
@@index([knowledgeBaseId, createdAt(sort: Desc)])
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/// A single text chunk inside a document. The `embedding` column is a
|
|
740
|
+
/// pgvector value; Prisma cannot generate types for it, so similarity
|
|
741
|
+
/// search must be performed via raw SQL (`$queryRaw`). The dimension is
|
|
742
|
+
/// fixed at 1536 to match `text-embedding-3-small`.
|
|
743
|
+
model KnowledgeBaseChunk {
|
|
744
|
+
id String @id @default(cuid())
|
|
745
|
+
documentId String
|
|
746
|
+
document KnowledgeBaseDocument @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
|
747
|
+
knowledgeBaseId String
|
|
748
|
+
chunkIndex Int
|
|
749
|
+
pageNumber Int?
|
|
750
|
+
content String
|
|
751
|
+
tokenCount Int?
|
|
752
|
+
embedding Unsupported("vector(1536)")?
|
|
753
|
+
createdAt DateTime @default(now())
|
|
754
|
+
|
|
755
|
+
@@index([knowledgeBaseId])
|
|
756
|
+
@@index([documentId, chunkIndex])
|
|
757
|
+
}
|
package/prisma/seed.mjs
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { PrismaClient } from '@prisma/client';
|
|
2
|
+
|
|
3
|
+
/** Keep in sync with server/src/lib/curated-kb-seed.ts */
|
|
4
|
+
const CURATED_KB_SEEDS = [
|
|
5
|
+
{ slug: 'ap-biology', name: 'AP Biology', description: 'Cell biology, genetics, evolution, and ecology aligned with the AP Biology curriculum.', category: 'AP', subject: 'biology' },
|
|
6
|
+
{ slug: 'ap-chemistry', name: 'AP Chemistry', description: 'Atomic structure, bonding, thermodynamics, and kinetics for AP Chemistry.', category: 'AP', subject: 'chemistry' },
|
|
7
|
+
{ slug: 'ap-physics-1', name: 'AP Physics 1', description: 'Algebra-based mechanics, waves, and electricity for AP Physics 1.', category: 'AP', subject: 'physics' },
|
|
8
|
+
{ slug: 'ap-calculus-ab', name: 'AP Calculus AB', description: 'Limits, derivatives, integrals, and the Fundamental Theorem of Calculus.', category: 'AP', subject: 'calculus' },
|
|
9
|
+
{ slug: 'ap-calculus-bc', name: 'AP Calculus BC', description: 'Series, parametric equations, polar coordinates, and advanced integration.', category: 'AP', subject: 'calculus' },
|
|
10
|
+
{ slug: 'ap-us-history', name: 'AP US History', description: 'Colonial America through the modern era with primary source analysis.', category: 'AP', subject: 'history' },
|
|
11
|
+
{ slug: 'ap-world-history', name: 'AP World History', description: 'Global civilizations, trade networks, and historical thinking skills.', category: 'AP', subject: 'history' },
|
|
12
|
+
{ slug: 'ap-english-lang', name: 'AP English Language', description: 'Rhetorical analysis, argumentation, and synthesis writing strategies.', category: 'AP', subject: 'english' },
|
|
13
|
+
{ slug: 'ap-english-lit', name: 'AP English Literature', description: 'Literary analysis, poetry, prose fiction, and critical essay writing.', category: 'AP', subject: 'literature' },
|
|
14
|
+
{ slug: 'ap-psychology', name: 'AP Psychology', description: 'Biological bases of behavior, cognition, development, and social psychology.', category: 'AP', subject: 'psychology' },
|
|
15
|
+
{ slug: 'ap-environmental-science', name: 'AP Environmental Science', description: 'Ecosystems, biodiversity, pollution, and sustainability concepts.', category: 'AP', subject: 'environmental' },
|
|
16
|
+
{ slug: 'ap-macroeconomics', name: 'AP Macroeconomics', description: 'GDP, inflation, fiscal and monetary policy, and international trade.', category: 'AP', subject: 'economics' },
|
|
17
|
+
{ slug: 'ib-biology-hl', name: 'IB Biology HL', description: 'Higher Level biology: molecular biology, genetics, ecology, and human physiology.', category: 'IB', subject: 'biology' },
|
|
18
|
+
{ slug: 'ib-chemistry-hl', name: 'IB Chemistry HL', description: 'Higher Level chemistry: organic, inorganic, physical, and analytical topics.', category: 'IB', subject: 'chemistry' },
|
|
19
|
+
{ slug: 'ib-physics-hl', name: 'IB Physics HL', description: 'Higher Level physics: mechanics, fields, waves, and nuclear physics.', category: 'IB', subject: 'physics' },
|
|
20
|
+
{ slug: 'ib-math-aa-hl', name: 'IB Math AA HL', description: 'Analysis & Approaches HL: calculus, proof, vectors, and complex numbers.', category: 'IB', subject: 'math' },
|
|
21
|
+
{ slug: 'ib-math-ai-hl', name: 'IB Math AI HL', description: 'Applications & Interpretation HL: statistics, modelling, and technology use.', category: 'IB', subject: 'math' },
|
|
22
|
+
{ slug: 'ib-history-hl', name: 'IB History HL', description: 'Higher Level history: 20th century world history and historical investigation.', category: 'IB', subject: 'history' },
|
|
23
|
+
{ slug: 'ib-english-a-hl', name: 'IB English A HL', description: 'Language & Literature HL: textual analysis, comparative study, and IO prep.', category: 'IB', subject: 'literature' },
|
|
24
|
+
{ slug: 'ib-economics-hl', name: 'IB Economics HL', description: 'Microeconomics, macroeconomics, international economics, and development.', category: 'IB', subject: 'economics' },
|
|
25
|
+
{ slug: 'ib-psychology-hl', name: 'IB Psychology HL', description: 'Biological, cognitive, sociocultural, and abnormal psychology at HL depth.', category: 'IB', subject: 'psychology' },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const prisma = new PrismaClient();
|
|
29
|
+
|
|
30
|
+
async function main() {
|
|
31
|
+
for (const seed of CURATED_KB_SEEDS) {
|
|
32
|
+
const existing = await prisma.knowledgeBase.findFirst({
|
|
33
|
+
where: { meta: { path: ['slug'], equals: seed.slug } },
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (existing) {
|
|
37
|
+
await prisma.knowledgeBase.update({
|
|
38
|
+
where: { id: existing.id },
|
|
39
|
+
data: {
|
|
40
|
+
name: seed.name,
|
|
41
|
+
description: seed.description,
|
|
42
|
+
isCurated: true,
|
|
43
|
+
meta: { slug: seed.slug, category: seed.category, subject: seed.subject },
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await prisma.knowledgeBase.create({
|
|
50
|
+
data: {
|
|
51
|
+
name: seed.name,
|
|
52
|
+
description: seed.description,
|
|
53
|
+
isCurated: true,
|
|
54
|
+
meta: { slug: seed.slug, category: seed.category, subject: seed.subject },
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log(`Seeded ${CURATED_KB_SEEDS.length} curated knowledge bases.`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
main()
|
|
63
|
+
.catch((e) => {
|
|
64
|
+
console.error(e);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
})
|
|
67
|
+
.finally(() => prisma.$disconnect());
|
package/src/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Server source layout
|
|
2
|
+
|
|
3
|
+
This server uses a layered architecture. Please keep new code in the right
|
|
4
|
+
layer so routers don't grow back to 1000+ lines again.
|
|
5
|
+
|
|
6
|
+
## Layers
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
tRPC Client -> routers/*.ts Zod input + middleware + glue
|
|
10
|
+
-> services/*.ts business logic and orchestration
|
|
11
|
+
-> repositories/*.ts Prisma queries
|
|
12
|
+
-> lib/* infra: email, pusher, stripe, storage,
|
|
13
|
+
inference, logger, errors, env, etc.
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
- `routers/` — **thin**. Each procedure:
|
|
17
|
+
1. Declares its Zod input schema.
|
|
18
|
+
2. Selects a procedure type (`authedProcedure`, `verifiedProcedure`, etc.).
|
|
19
|
+
3. Instantiates a service (`new FooService(ctx.db)`) and returns its result.
|
|
20
|
+
4. Optionally handles transport-only concerns (e.g. cookies in
|
|
21
|
+
`auth.ts`).
|
|
22
|
+
5. Does **not** call Prisma directly. Does **not** contain business
|
|
23
|
+
logic beyond trivial response shaping.
|
|
24
|
+
- `services/` — **business logic**. One service per domain aggregate.
|
|
25
|
+
Constructor signature is `(db: PrismaClient)` via `BaseService`. Services
|
|
26
|
+
can depend on other services and on repositories, but must **not**
|
|
27
|
+
depend on `Context`, `Request`, or other HTTP types.
|
|
28
|
+
- `repositories/` — **data access**. Thin Prisma wrappers per aggregate.
|
|
29
|
+
Expose intent-revealing methods (`findAccessibleById`, `listOwned`) so
|
|
30
|
+
the shape of `where` clauses doesn't leak into services.
|
|
31
|
+
- `lib/` — infrastructure and pure utilities: Prisma client singleton,
|
|
32
|
+
Stripe SDK, email transport, Pusher client, Supabase client, logger,
|
|
33
|
+
shared error classes, env validation, retry helper, validation helpers.
|
|
34
|
+
**Not** domain services.
|
|
35
|
+
|
|
36
|
+
## Conventions
|
|
37
|
+
|
|
38
|
+
- **File naming**: `{kebab-case-domain}.service.ts`,
|
|
39
|
+
`{kebab-case-domain}.repository.ts` (singular).
|
|
40
|
+
- **Class naming**: `FooService`, `FooRepository`.
|
|
41
|
+
- **Constructor injection**: every service/repository takes a
|
|
42
|
+
`PrismaClient` in its constructor. Instantiate per-request from the
|
|
43
|
+
router (`new FooService(ctx.db)`).
|
|
44
|
+
- **Workspace access**: use `workspaceAccessWhere(userId)` from
|
|
45
|
+
`repositories/workspace.repository.ts` for member-inclusive access, or
|
|
46
|
+
`workspaceOwnerWhere(userId)` for owner-only. Don't hand-roll
|
|
47
|
+
`OR: [{ ownerId }, …]` again.
|
|
48
|
+
- **Errors**: throw `TRPCError` for HTTP-shaped errors in services. They
|
|
49
|
+
propagate cleanly back through the router.
|
|
50
|
+
|
|
51
|
+
## Folders
|
|
52
|
+
|
|
53
|
+
- `context.ts` — tRPC context builder (session + db + req/res).
|
|
54
|
+
- `trpc.ts` — procedure types and middleware (auth, verification, plan
|
|
55
|
+
limits, activity logging).
|
|
56
|
+
- `routers/` — one file per top-level router, plus `_app.ts` composition.
|
|
57
|
+
- `services/` — domain services (router → service → repository).
|
|
58
|
+
- `repositories/` — Prisma access per aggregate.
|
|
59
|
+
- `lib/` — infrastructure and shared utilities.
|
|
60
|
+
- `types/` — shared TS types.
|
|
61
|
+
- `scripts/` — operational tooling (cron-style tasks).
|
|
62
|
+
|
|
63
|
+
See `REFACTOR_NOTES.md` at the repo root for known follow-up work.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const aiConfig = {
|
|
2
|
+
llm: {
|
|
3
|
+
apiKey: process.env.INFERENCE_API_KEY,
|
|
4
|
+
baseUrl: process.env.INFERENCE_BASE_URL,
|
|
5
|
+
model: process.env.INFERENCE_MODEL ?? 'command-a-03-2025',
|
|
6
|
+
},
|
|
7
|
+
embeddings: {
|
|
8
|
+
apiKey:
|
|
9
|
+
process.env.OPENAI_API_KEY,
|
|
10
|
+
baseUrl:
|
|
11
|
+
undefined,
|
|
12
|
+
model: process.env.EMBEDDING_MODEL ?? 'text-embedding-3-small',
|
|
13
|
+
dim: Number(process.env.EMBEDDING_DIM ?? 1536),
|
|
14
|
+
},
|
|
15
|
+
inferenceBackend: {
|
|
16
|
+
url: process.env.INFERENCE_API_URL,
|
|
17
|
+
mockEnabled: process.env.DONT_TEST_INFERENCE === 'true',
|
|
18
|
+
mockDelayMs: process.env.DONT_TEST_INFERENCE === 'true' ? 10_000 : 0,
|
|
19
|
+
},
|
|
20
|
+
} as const;
|
|
21
|
+
|
|
22
|
+
export function getInferenceBackendUploadUrl(): string {
|
|
23
|
+
const base = aiConfig.inferenceBackend.url;
|
|
24
|
+
if (!base) {
|
|
25
|
+
throw new Error('INFERENCE_API_URL is not configured');
|
|
26
|
+
}
|
|
27
|
+
return `${base.replace(/\/$/, '')}/upload`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function tryGetInferenceBackendUploadUrl(): string | null {
|
|
31
|
+
const base = aiConfig.inferenceBackend.url;
|
|
32
|
+
if (!base) return null;
|
|
33
|
+
return `${base.replace(/\/$/, '')}/upload`;
|
|
34
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
import { aiConfig } from './config.js';
|
|
3
|
+
|
|
4
|
+
const client = new OpenAI({
|
|
5
|
+
apiKey: aiConfig.embeddings.apiKey,
|
|
6
|
+
baseURL: aiConfig.embeddings.baseUrl,
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export const DEFAULT_EMBEDDING_MODEL = aiConfig.embeddings.model;
|
|
10
|
+
export const DEFAULT_EMBEDDING_DIM = aiConfig.embeddings.dim;
|
|
11
|
+
|
|
12
|
+
export interface EmbedOptions {
|
|
13
|
+
model?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function embedTexts(
|
|
17
|
+
texts: string[],
|
|
18
|
+
opts: EmbedOptions = {},
|
|
19
|
+
): Promise<number[][]> {
|
|
20
|
+
const model = opts.model ?? DEFAULT_EMBEDDING_MODEL;
|
|
21
|
+
|
|
22
|
+
if (texts.length === 0) return [];
|
|
23
|
+
|
|
24
|
+
const BATCH = 96;
|
|
25
|
+
const out: number[][] = new Array(texts.length);
|
|
26
|
+
for (let i = 0; i < texts.length; i += BATCH) {
|
|
27
|
+
const batch = texts.slice(i, i + BATCH);
|
|
28
|
+
|
|
29
|
+
const res = await client.embeddings.create({ model, input: batch });
|
|
30
|
+
res.data.forEach((row, j) => {
|
|
31
|
+
out[i + j] = row.embedding as number[];
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function embedQuery(
|
|
38
|
+
text: string,
|
|
39
|
+
opts: EmbedOptions = {},
|
|
40
|
+
): Promise<number[]> {
|
|
41
|
+
const [vec] = await embedTexts([text], opts);
|
|
42
|
+
return vec;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function toVectorLiteral(vec: number[]): string {
|
|
46
|
+
return `[${vec.map((n) => (Number.isFinite(n) ? n : 0)).join(',')}]`;
|
|
47
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { aiConfig } from './config.js';
|
|
2
|
+
import {
|
|
3
|
+
complete,
|
|
4
|
+
completeText,
|
|
5
|
+
} from './llm-client.js';
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_EMBEDDING_DIM,
|
|
8
|
+
DEFAULT_EMBEDDING_MODEL,
|
|
9
|
+
embedQuery,
|
|
10
|
+
embedTexts,
|
|
11
|
+
toVectorLiteral,
|
|
12
|
+
} from './embedding-client.js';
|
|
13
|
+
import { extractJson, parseJsonField } from './json-parse.js';
|
|
14
|
+
import { isAiMockMode, mockDelay } from './mock.js';
|
|
15
|
+
import { inferenceBackend } from './inference-backend/client.js';
|
|
16
|
+
|
|
17
|
+
export const ai = {
|
|
18
|
+
config: aiConfig,
|
|
19
|
+
isMockMode: isAiMockMode,
|
|
20
|
+
mockDelay,
|
|
21
|
+
llm: {
|
|
22
|
+
complete,
|
|
23
|
+
completeText,
|
|
24
|
+
},
|
|
25
|
+
embed: {
|
|
26
|
+
texts: embedTexts,
|
|
27
|
+
query: embedQuery,
|
|
28
|
+
toVectorLiteral,
|
|
29
|
+
DEFAULT_MODEL: DEFAULT_EMBEDDING_MODEL,
|
|
30
|
+
DEFAULT_DIM: DEFAULT_EMBEDDING_DIM,
|
|
31
|
+
},
|
|
32
|
+
backend: inferenceBackend,
|
|
33
|
+
parse: {
|
|
34
|
+
extractJson,
|
|
35
|
+
parseJsonField,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type { ChatMessage, ChatRole, CompleteOptions } from './types.js';
|
|
40
|
+
export type {
|
|
41
|
+
AISession,
|
|
42
|
+
ProcessFileResult,
|
|
43
|
+
PodcastSpeaker,
|
|
44
|
+
StudyGuideSegment,
|
|
45
|
+
WorksheetGenerationOptions,
|
|
46
|
+
} from './inference-backend/types.js';
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
aiConfig,
|
|
50
|
+
complete,
|
|
51
|
+
completeText,
|
|
52
|
+
DEFAULT_EMBEDDING_DIM,
|
|
53
|
+
DEFAULT_EMBEDDING_MODEL,
|
|
54
|
+
embedQuery,
|
|
55
|
+
embedTexts,
|
|
56
|
+
extractJson,
|
|
57
|
+
inferenceBackend,
|
|
58
|
+
isAiMockMode,
|
|
59
|
+
mockDelay,
|
|
60
|
+
parseJsonField,
|
|
61
|
+
toVectorLiteral,
|
|
62
|
+
};
|