@danielcok17/prisma-db 1.19.0 → 1.19.2
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/dist/migrations/migrateIngestedDocuments.d.ts +17 -0
- package/dist/migrations/migrateIngestedDocuments.d.ts.map +1 -0
- package/dist/migrations/migrateIngestedDocuments.js +113 -0
- package/dist/migrations/migrateIngestedDocuments.js.map +1 -0
- package/dist/migrations/migrateMessageFiles.d.ts +14 -0
- package/dist/migrations/migrateMessageFiles.d.ts.map +1 -0
- package/dist/migrations/migrateMessageFiles.js +120 -0
- package/dist/migrations/migrateMessageFiles.js.map +1 -0
- package/package.json +2 -1
- package/prisma/app.prisma +33 -10
- package/prisma/migrations/20260502204440_add_userfile_source_tracking/migration.sql +50 -0
- package/prisma/migrations/20260503104028_add_canvas_source_and_ai_generated/migration.sql +5 -0
|
@@ -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":";AAAA;;;;;;;;;;;;;;GAcG;;;;;AAEH,oDAA0D;AAC1D,oDAA4B;AAE5B,MAAM,MAAM,GAAG,IAAI,kBAAY,EAAE,CAAC;AAElC,KAAK,UAAU,wBAAwB;IACrC,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;IAE5D,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,SAAS,CAqBlC,8FAA8F,CAAC;IAEhG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,MAAM,4BAA4B,CAAC,CAAC;IAElE,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC;YACH,oDAAoD;YACpD,IAAI,UAAU,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC;YAE3D,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,OAAO,CAAC,IAAI,CAAC,oBAAoB,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,QAAQ,sBAAsB,CAAC,CAAC;gBAChF,OAAO,EAAE,CAAC;gBACV,SAAS;YACX,CAAC;YAED,yCAAyC;YACzC,IAAI,UAAU,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBACtC,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;oBAChC,UAAU,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,uBAAuB;gBAC9E,CAAC;gBAAC,MAAM,CAAC;oBACP,gBAAgB;gBAClB,CAAC;YACH,CAAC;YAED,qCAAqC;YACrC,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;gBACpB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;oBAC/C,KAAK,EAAE,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE;iBACxC,CAAC,CAAC;gBACH,IAAI,QAAQ,EAAE,CAAC;oBACb,OAAO,CAAC,GAAG,CAAC,4BAA4B,GAAG,CAAC,WAAW,oBAAoB,CAAC,CAAC;oBAC7E,OAAO,EAAE,CAAC;oBACV,SAAS;gBACX,CAAC;YACH,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC5C,IAAI,EAAE;oBACJ,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,UAAU;oBACV,+EAA+E;oBAC/E,8DAA8D;oBAC9D,+EAA+E;oBAC/E,cAAc,EAAE,YAAY,gBAAM,CAAC,UAAU,EAAE,EAAE;oBACjD,QAAQ,EAAE,GAAG,CAAC,QAAQ;oBACtB,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,iBAAiB;oBAC3C,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,CAAC;oBAC3B,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ;oBACzD,OAAO,EAAE,GAAG,CAAC,OAAO;oBACpB,SAAS,EAAE,GAAG,CAAC,SAAS;oBACxB,OAAO,EAAE,GAAG,CAAC,OAAO;oBACpB,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,EAAE;oBAChC,UAAU,EAAE,GAAG,CAAC,UAAU;oBAC1B,WAAW,EAAE,GAAG,CAAC,WAAW;oBAC5B,YAAY,EAAE,GAAG,CAAC,aAAa;oBAC/B,SAAS,EAAE,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;oBAC5D,IAAI,EAAE,EAAE;oBACR,SAAS,EAAE,GAAG,CAAC,SAAS;iBACzB;aACF,CAAC,CAAC;YAEH,oCAAoC;YACpC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;gBACjB,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;oBAC7B,IAAI,EAAE;wBACJ,QAAQ,EAAE,GAAG,CAAC,QAAQ;wBACtB,UAAU,EAAE,WAAW;wBACvB,QAAQ,EAAE,QAAQ,CAAC,EAAE;wBACrB,SAAS,EAAE,GAAG,CAAC,MAAM;wBACrB,SAAS,EAAE,CAAC;qBACb;iBACF,CAAC,CAAC;YACL,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,CAAC,QAAQ,aAAa,GAAG,CAAC,MAAM,MAAM,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;YACvF,QAAQ,EAAE,CAAC;QACb,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,uCAAuC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;YACrE,MAAM,EAAE,CAAC;QACX,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,kBAAkB,QAAQ,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,WAAW,MAAM,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,wBAAwB,EAAE;KACvB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;KACpB,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC"}
|
|
@@ -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.
|
|
3
|
+
"version": "1.19.2",
|
|
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,13 @@ 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
|
+
CANVAS // AI-vygenerovaný dokument uložený z canvas editora
|
|
934
|
+
}
|
|
935
|
+
|
|
930
936
|
enum IndexingJobStatus {
|
|
931
937
|
QUEUED
|
|
932
938
|
RUNNING
|
|
@@ -1153,28 +1159,45 @@ model UserFile {
|
|
|
1153
1159
|
parentFileId String?
|
|
1154
1160
|
versionNumber Int @default(1)
|
|
1155
1161
|
|
|
1156
|
-
|
|
1162
|
+
uploadSource UserFileUploadSource @default(STORAGE)
|
|
1163
|
+
uploadContextId String? // polymorphic: folderId | conversationId | documentId | null
|
|
1164
|
+
isAiGenerated Boolean @default(false) // true = AI vygeneroval obsah (canvas export)
|
|
1157
1165
|
|
|
1158
1166
|
createdAt DateTime @default(now())
|
|
1159
1167
|
updatedAt DateTime @updatedAt
|
|
1160
1168
|
deletedAt DateTime?
|
|
1161
1169
|
|
|
1162
|
-
user
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1170
|
+
user User @relation("UserFiles", fields: [userId], references: [id], onDelete: Cascade)
|
|
1171
|
+
indexingJobs FileIndexingJob[]
|
|
1172
|
+
deadlines FileDeadline[]
|
|
1173
|
+
parentFile UserFile? @relation("FileVersions", fields: [parentFileId], references: [id], onDelete: SetNull)
|
|
1174
|
+
childVersions UserFile[] @relation("FileVersions")
|
|
1175
|
+
conversationUsages UserFileConversation[]
|
|
1168
1176
|
|
|
1169
1177
|
@@index([userId])
|
|
1170
1178
|
@@index([status])
|
|
1171
1179
|
@@index([userId, status])
|
|
1172
1180
|
@@index([userId, deletedAt])
|
|
1173
1181
|
@@index([qdrantDocId])
|
|
1174
|
-
@@index([
|
|
1182
|
+
@@index([uploadSource])
|
|
1183
|
+
@@index([uploadContextId])
|
|
1175
1184
|
@@index([checksumSha256])
|
|
1176
1185
|
}
|
|
1177
1186
|
|
|
1187
|
+
model UserFileConversation {
|
|
1188
|
+
id String @id @default(cuid())
|
|
1189
|
+
fileId String
|
|
1190
|
+
conversationId String
|
|
1191
|
+
createdAt DateTime @default(now())
|
|
1192
|
+
|
|
1193
|
+
file UserFile @relation(fields: [fileId], references: [id], onDelete: Cascade)
|
|
1194
|
+
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
|
|
1195
|
+
|
|
1196
|
+
@@unique([fileId, conversationId])
|
|
1197
|
+
@@index([fileId])
|
|
1198
|
+
@@index([conversationId])
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1178
1201
|
model FileIndexingJob {
|
|
1179
1202
|
id String @id @default(cuid())
|
|
1180
1203
|
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;
|