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