@danielcok17/prisma-db 1.19.0 → 1.19.1

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.
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Migrácia IngestedDocument → UserFile
3
+ *
4
+ * IngestedDocument.storageUrl (DO Spaces) → UserFile.storageKey
5
+ * IngestedDocument.qdrantDocId → UserFile.qdrantDocId
6
+ * IngestedDocument status COMPLETED → UserFile status INDEXED
7
+ *
8
+ * PRED spustením:
9
+ * 1. Nastav DATABASE_URL env var
10
+ * 2. Over že UserFile tabuľka existuje
11
+ * 3. Spusti v staging/dev NAJPRV
12
+ *
13
+ * Spustenie: npx tsx src/migrations/migrateIngestedDocuments.ts
14
+ * Rollback: IngestedDocument záznamy sa NEMAŽÚ
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=migrateIngestedDocuments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrateIngestedDocuments.d.ts","sourceRoot":"","sources":["../../src/migrations/migrateIngestedDocuments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ /**
3
+ * Migrácia IngestedDocument → UserFile
4
+ *
5
+ * IngestedDocument.storageUrl (DO Spaces) → UserFile.storageKey
6
+ * IngestedDocument.qdrantDocId → UserFile.qdrantDocId
7
+ * IngestedDocument status COMPLETED → UserFile status INDEXED
8
+ *
9
+ * PRED spustením:
10
+ * 1. Nastav DATABASE_URL env var
11
+ * 2. Over že UserFile tabuľka existuje
12
+ * 3. Spusti v staging/dev NAJPRV
13
+ *
14
+ * Spustenie: npx tsx src/migrations/migrateIngestedDocuments.ts
15
+ * Rollback: IngestedDocument záznamy sa NEMAŽÚ
16
+ */
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ const app_1 = require("../../prisma/generated/app");
22
+ const crypto_1 = __importDefault(require("crypto"));
23
+ const prisma = new app_1.PrismaClient();
24
+ async function migrateIngestedDocuments() {
25
+ console.log("Začínam migráciu IngestedDocument → UserFile");
26
+ const docs = await prisma.$queryRaw `SELECT * FROM "IngestedDocument" WHERE "storageUrl" IS NOT NULL OR "storagePath" IS NOT NULL`;
27
+ console.log(`Nájdených ${docs.length} IngestedDocument záznamov`);
28
+ let migrated = 0;
29
+ let skipped = 0;
30
+ let errors = 0;
31
+ for (const doc of docs) {
32
+ try {
33
+ // Odvodni storageKey z storageUrl alebo storagePath
34
+ let storageKey = doc.storageUrl || doc.storagePath || null;
35
+ if (!storageKey) {
36
+ console.warn(`IngestedDocument ${doc.id} (${doc.fileName}) nemá storage, skip`);
37
+ skipped++;
38
+ continue;
39
+ }
40
+ // Ak je to full URL, extrahuj path (key)
41
+ if (storageKey.startsWith("https://")) {
42
+ try {
43
+ const url = new URL(storageKey);
44
+ storageKey = url.pathname.replace(/^\/[^/]+\//, ""); // odober bucket z path
45
+ }
46
+ catch {
47
+ // nechaj ako je
48
+ }
49
+ }
50
+ // Skontroluj dedup podľa qdrantDocId
51
+ if (doc.qdrantDocId) {
52
+ const existing = await prisma.userFile.findFirst({
53
+ where: { qdrantDocId: doc.qdrantDocId },
54
+ });
55
+ if (existing) {
56
+ console.log(`UserFile pre qdrantDocId ${doc.qdrantDocId} už existuje, skip`);
57
+ skipped++;
58
+ continue;
59
+ }
60
+ }
61
+ const userFile = await prisma.userFile.create({
62
+ data: {
63
+ userId: doc.userId,
64
+ storageKey,
65
+ // PLACEHOLDER: SHA-256 nie je dostupné pre migrované IngestedDocument záznamy.
66
+ // Dedup cez checksumSha256 nebude fungovať pre tieto záznamy.
67
+ // Po migrácii: ak je potrebný skutočný hash, stiahnuť súbor z S3 a prepočítať.
68
+ checksumSha256: `migrated_${crypto_1.default.randomUUID()}`,
69
+ fileName: doc.fileName,
70
+ fileType: doc.fileType || "application/pdf",
71
+ fileSize: doc.fileSize || 0,
72
+ status: doc.status === "COMPLETED" ? "INDEXED" : "STORED",
73
+ docType: doc.docType,
74
+ legalArea: doc.legalArea,
75
+ summary: doc.summary,
76
+ references: doc.references || [],
77
+ chunkCount: doc.chunkCount,
78
+ qdrantDocId: doc.qdrantDocId,
79
+ indexingCost: doc.embeddingCost,
80
+ indexedAt: doc.status === "COMPLETED" ? doc.updatedAt : null,
81
+ tags: [],
82
+ createdAt: doc.createdAt,
83
+ },
84
+ });
85
+ // Ak má folderId, vytvor FolderItem
86
+ if (doc.folderId) {
87
+ await prisma.folderItem.create({
88
+ data: {
89
+ folderId: doc.folderId,
90
+ entityType: "USER_FILE",
91
+ entityId: userFile.id,
92
+ addedById: doc.userId,
93
+ sortOrder: 0,
94
+ },
95
+ });
96
+ }
97
+ console.log(`Migrovaný: ${doc.fileName} (status: ${doc.status} → ${userFile.status})`);
98
+ migrated++;
99
+ }
100
+ catch (err) {
101
+ console.error(`Chyba pri migrácii IngestedDocument ${doc.id}:`, err);
102
+ errors++;
103
+ }
104
+ }
105
+ console.log("\nVýsledok:");
106
+ console.log(` Migrovaných: ${migrated}`);
107
+ console.log(` Preskočených: ${skipped}`);
108
+ console.log(` Chýb: ${errors}`);
109
+ }
110
+ migrateIngestedDocuments()
111
+ .catch(console.error)
112
+ .finally(() => prisma.$disconnect());
113
+ //# sourceMappingURL=migrateIngestedDocuments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrateIngestedDocuments.js","sourceRoot":"","sources":["../../src/migrations/migrateIngestedDocuments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Migrácia MessageFile (base64 v DB) → UserFile (S3/DO Spaces)
3
+ *
4
+ * PRED spustením:
5
+ * 1. Nastav env vars: DO_SPACES_ENDPOINT, DO_SPACES_REGION, DO_SPACES_BUCKET,
6
+ * DO_SPACES_ACCESS_KEY, DO_SPACES_SECRET_KEY, DATABASE_URL
7
+ * 2. Over že UserFile tabuľka existuje (migrácia 20260502185044_add_userfile_system)
8
+ * 3. Spusti v staging/dev NAJPRV pred prod
9
+ *
10
+ * Spustenie: npx tsx src/migrations/migrateMessageFiles.ts
11
+ * Rollback: MessageFile záznamy sa NEMAŽÚ — rollback = vyčisti UserFile záznamy
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=migrateMessageFiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrateMessageFiles.d.ts","sourceRoot":"","sources":["../../src/migrations/migrateMessageFiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ /**
3
+ * Migrácia MessageFile (base64 v DB) → UserFile (S3/DO Spaces)
4
+ *
5
+ * PRED spustením:
6
+ * 1. Nastav env vars: DO_SPACES_ENDPOINT, DO_SPACES_REGION, DO_SPACES_BUCKET,
7
+ * DO_SPACES_ACCESS_KEY, DO_SPACES_SECRET_KEY, DATABASE_URL
8
+ * 2. Over že UserFile tabuľka existuje (migrácia 20260502185044_add_userfile_system)
9
+ * 3. Spusti v staging/dev NAJPRV pred prod
10
+ *
11
+ * Spustenie: npx tsx src/migrations/migrateMessageFiles.ts
12
+ * Rollback: MessageFile záznamy sa NEMAŽÚ — rollback = vyčisti UserFile záznamy
13
+ */
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ const app_1 = require("../../prisma/generated/app");
19
+ const client_s3_1 = require("@aws-sdk/client-s3");
20
+ const crypto_1 = __importDefault(require("crypto"));
21
+ const prisma = new app_1.PrismaClient();
22
+ const s3 = new client_s3_1.S3Client({
23
+ endpoint: process.env.DO_SPACES_ENDPOINT || "https://fra1.digitaloceanspaces.com",
24
+ region: process.env.DO_SPACES_REGION || "fra1",
25
+ credentials: {
26
+ accessKeyId: process.env.DO_SPACES_ACCESS_KEY || "",
27
+ secretAccessKey: process.env.DO_SPACES_SECRET_KEY || "",
28
+ },
29
+ });
30
+ const BUCKET = process.env.DO_SPACES_BUCKET || "smartlex-user-files";
31
+ async function migrateMessageFiles() {
32
+ console.log("Začínam migráciu MessageFile → UserFile");
33
+ // Nájdi všetky FolderItem záznamy s entityType=ATTACHMENT
34
+ const attachments = await prisma.folderItem.findMany({
35
+ where: { entityType: "ATTACHMENT" },
36
+ });
37
+ console.log(`Nájdených ${attachments.length} ATTACHMENT FolderItem záznamov`);
38
+ let migrated = 0;
39
+ let skipped = 0;
40
+ let errors = 0;
41
+ for (const attachment of attachments) {
42
+ try {
43
+ // Načítaj MessageFile cez raw query (Prisma ho môže nemať ako typed model)
44
+ const messageFiles = await prisma.$queryRaw `SELECT id, "fileName", "fileType", "base64Data", "uploadedAt" FROM "MessageFile" WHERE id = ${attachment.entityId}`;
45
+ if (!messageFiles[0]) {
46
+ console.warn(`MessageFile ${attachment.entityId} nenájdený, skip`);
47
+ skipped++;
48
+ continue;
49
+ }
50
+ const mf = messageFiles[0];
51
+ // Dekóduj base64 → buffer
52
+ if (!mf.base64Data) {
53
+ console.warn(`MessageFile ${mf.id} (${mf.fileName}) má prázdny base64Data, skip`);
54
+ skipped++;
55
+ continue;
56
+ }
57
+ const buffer = Buffer.from(mf.base64Data, "base64");
58
+ const checksumSha256 = crypto_1.default.createHash("sha256").update(buffer).digest("hex");
59
+ // Skontroluj dedup podľa checksum
60
+ const existing = await prisma.userFile.findFirst({
61
+ where: { checksumSha256 },
62
+ });
63
+ if (existing) {
64
+ console.log(`UserFile pre checksum ${checksumSha256.substring(0, 8)}... už existuje, aktualizujem FolderItem`);
65
+ await prisma.folderItem.update({
66
+ where: { id: attachment.id },
67
+ data: { entityType: "USER_FILE", entityId: existing.id },
68
+ });
69
+ migrated++;
70
+ continue;
71
+ }
72
+ // Upload do S3
73
+ const userId = attachment.addedById;
74
+ const uuid = crypto_1.default.randomUUID();
75
+ const safe = (mf.fileName || "file").replace(/[^a-zA-Z0-9._-]/g, "_");
76
+ const storageKey = `users/${userId}/files/migrated_${uuid}_${safe}`;
77
+ await s3.send(new client_s3_1.PutObjectCommand({
78
+ Bucket: BUCKET,
79
+ Key: storageKey,
80
+ Body: buffer,
81
+ ContentType: mf.fileType || "application/octet-stream",
82
+ ContentLength: buffer.length,
83
+ }));
84
+ // Vytvor UserFile
85
+ const userFile = await prisma.userFile.create({
86
+ data: {
87
+ userId,
88
+ storageKey,
89
+ checksumSha256,
90
+ fileName: mf.fileName || "unknown",
91
+ fileType: mf.fileType || "application/octet-stream",
92
+ fileSize: buffer.length,
93
+ status: "STORED",
94
+ tags: [],
95
+ references: [],
96
+ createdAt: mf.uploadedAt,
97
+ },
98
+ });
99
+ // Aktualizuj FolderItem: ATTACHMENT → USER_FILE
100
+ await prisma.folderItem.update({
101
+ where: { id: attachment.id },
102
+ data: { entityType: "USER_FILE", entityId: userFile.id },
103
+ });
104
+ console.log(`Migrovaný: ${mf.fileName} (${buffer.length} bytes) → ${storageKey}`);
105
+ migrated++;
106
+ }
107
+ catch (err) {
108
+ console.error(`Chyba pri migrácii attachment ${attachment.id}:`, err);
109
+ errors++;
110
+ }
111
+ }
112
+ console.log("\nVýsledok migrácie:");
113
+ console.log(` Migrovaných: ${migrated}`);
114
+ console.log(` Preskočených: ${skipped}`);
115
+ console.log(` Chýb: ${errors}`);
116
+ }
117
+ migrateMessageFiles()
118
+ .catch(console.error)
119
+ .finally(() => prisma.$disconnect());
120
+ //# sourceMappingURL=migrateMessageFiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrateMessageFiles.js","sourceRoot":"","sources":["../../src/migrations/migrateMessageFiles.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danielcok17/prisma-db",
3
- "version": "1.19.0",
3
+ "version": "1.19.1",
4
4
  "description": "Shared Prisma schema for Legal AI applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -39,6 +39,7 @@
39
39
  "@prisma/client": "^6.17.0"
40
40
  },
41
41
  "devDependencies": {
42
+ "@aws-sdk/client-s3": "^3.1041.0",
42
43
  "@types/node": "^24.3.0",
43
44
  "prisma": "^6.17.0",
44
45
  "tsx": "^4.0.0",
package/prisma/app.prisma CHANGED
@@ -298,6 +298,7 @@ model Conversation {
298
298
  user User @relation(fields: [userId], references: [id])
299
299
  workflowLogs WorkflowLog[]
300
300
  canvasDocuments CanvasDocument[]
301
+ fileUsages UserFileConversation[]
301
302
 
302
303
  @@index([userId])
303
304
  @@index([createdAt])
@@ -330,8 +331,6 @@ model Answer {
330
331
  WorkflowLog WorkflowLog[]
331
332
  files MessageFile[]
332
333
  canvasDocumentId String? // No FK constraint - flexible document management
333
- userFiles UserFile[] @relation("UserFileAnswers")
334
-
335
334
  @@index([conversationId])
336
335
  @@index([messageId])
337
336
  @@index([role])
@@ -927,6 +926,12 @@ enum UserFileStatus {
927
926
  DELETED
928
927
  }
929
928
 
929
+ enum UserFileUploadSource {
930
+ FOLDER // nahraté cez UI priečinka / prípadu
931
+ CHAT // nahraté z chatovej konverzácie
932
+ STORAGE // nahraté priamo do "Môj archív"
933
+ }
934
+
930
935
  enum IndexingJobStatus {
931
936
  QUEUED
932
937
  RUNNING
@@ -1153,28 +1158,44 @@ model UserFile {
1153
1158
  parentFileId String?
1154
1159
  versionNumber Int @default(1)
1155
1160
 
1156
- answerId String?
1161
+ uploadSource UserFileUploadSource @default(STORAGE)
1162
+ uploadContextId String? // polymorphic: folderId | conversationId | null
1157
1163
 
1158
1164
  createdAt DateTime @default(now())
1159
1165
  updatedAt DateTime @updatedAt
1160
1166
  deletedAt DateTime?
1161
1167
 
1162
- user User @relation("UserFiles", fields: [userId], references: [id], onDelete: Cascade)
1163
- answer Answer? @relation("UserFileAnswers", fields: [answerId], references: [id], onDelete: SetNull)
1164
- indexingJobs FileIndexingJob[]
1165
- deadlines FileDeadline[]
1166
- parentFile UserFile? @relation("FileVersions", fields: [parentFileId], references: [id], onDelete: SetNull)
1167
- childVersions UserFile[] @relation("FileVersions")
1168
+ user User @relation("UserFiles", fields: [userId], references: [id], onDelete: Cascade)
1169
+ indexingJobs FileIndexingJob[]
1170
+ deadlines FileDeadline[]
1171
+ parentFile UserFile? @relation("FileVersions", fields: [parentFileId], references: [id], onDelete: SetNull)
1172
+ childVersions UserFile[] @relation("FileVersions")
1173
+ conversationUsages UserFileConversation[]
1168
1174
 
1169
1175
  @@index([userId])
1170
1176
  @@index([status])
1171
1177
  @@index([userId, status])
1172
1178
  @@index([userId, deletedAt])
1173
1179
  @@index([qdrantDocId])
1174
- @@index([answerId])
1180
+ @@index([uploadSource])
1181
+ @@index([uploadContextId])
1175
1182
  @@index([checksumSha256])
1176
1183
  }
1177
1184
 
1185
+ model UserFileConversation {
1186
+ id String @id @default(cuid())
1187
+ fileId String
1188
+ conversationId String
1189
+ createdAt DateTime @default(now())
1190
+
1191
+ file UserFile @relation(fields: [fileId], references: [id], onDelete: Cascade)
1192
+ conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
1193
+
1194
+ @@unique([fileId, conversationId])
1195
+ @@index([fileId])
1196
+ @@index([conversationId])
1197
+ }
1198
+
1178
1199
  model FileIndexingJob {
1179
1200
  id String @id @default(cuid())
1180
1201
  fileId String
@@ -0,0 +1,50 @@
1
+ /*
2
+ Warnings:
3
+
4
+ - You are about to drop the column `answerId` on the `UserFile` table. All the data in the column will be lost.
5
+
6
+ */
7
+ -- CreateEnum
8
+ CREATE TYPE "UserFileUploadSource" AS ENUM ('FOLDER', 'CHAT', 'STORAGE');
9
+
10
+ -- DropForeignKey
11
+ ALTER TABLE "public"."UserFile" DROP CONSTRAINT "UserFile_answerId_fkey";
12
+
13
+ -- DropIndex
14
+ DROP INDEX "public"."UserFile_answerId_idx";
15
+
16
+ -- AlterTable
17
+ ALTER TABLE "UserFile" DROP COLUMN "answerId",
18
+ ADD COLUMN "uploadContextId" TEXT,
19
+ ADD COLUMN "uploadSource" "UserFileUploadSource" NOT NULL DEFAULT 'STORAGE';
20
+
21
+ -- CreateTable
22
+ CREATE TABLE "UserFileConversation" (
23
+ "id" TEXT NOT NULL,
24
+ "fileId" TEXT NOT NULL,
25
+ "conversationId" TEXT NOT NULL,
26
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
27
+
28
+ CONSTRAINT "UserFileConversation_pkey" PRIMARY KEY ("id")
29
+ );
30
+
31
+ -- CreateIndex
32
+ CREATE INDEX "UserFileConversation_fileId_idx" ON "UserFileConversation"("fileId");
33
+
34
+ -- CreateIndex
35
+ CREATE INDEX "UserFileConversation_conversationId_idx" ON "UserFileConversation"("conversationId");
36
+
37
+ -- CreateIndex
38
+ CREATE UNIQUE INDEX "UserFileConversation_fileId_conversationId_key" ON "UserFileConversation"("fileId", "conversationId");
39
+
40
+ -- CreateIndex
41
+ CREATE INDEX "UserFile_uploadSource_idx" ON "UserFile"("uploadSource");
42
+
43
+ -- CreateIndex
44
+ CREATE INDEX "UserFile_uploadContextId_idx" ON "UserFile"("uploadContextId");
45
+
46
+ -- AddForeignKey
47
+ ALTER TABLE "UserFileConversation" ADD CONSTRAINT "UserFileConversation_fileId_fkey" FOREIGN KEY ("fileId") REFERENCES "UserFile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
48
+
49
+ -- AddForeignKey
50
+ ALTER TABLE "UserFileConversation" ADD CONSTRAINT "UserFileConversation_conversationId_fkey" FOREIGN KEY ("conversationId") REFERENCES "Conversation"("id") ON DELETE CASCADE ON UPDATE CASCADE;