@danielcok17/prisma-db 1.18.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.18.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
@@ -137,6 +137,11 @@ model User {
137
137
  sequenceEnrollments EmailSequenceEnrollment[]
138
138
  referralsSent Referral[] @relation("ReferralsSent")
139
139
  referralsReceived Referral[] @relation("ReferralsReceived")
140
+ // Files & folders system
141
+ userFiles UserFile[] @relation("UserFiles")
142
+ reviewTables FileReviewTable[] @relation("UserReviewTables")
143
+ filesTotalBytes BigInt @default(0)
144
+ filesCount Int @default(0)
140
145
 
141
146
  // Multi-brand: compound unique allows same email across brands
142
147
  @@unique([email, brand])
@@ -293,6 +298,7 @@ model Conversation {
293
298
  user User @relation(fields: [userId], references: [id])
294
299
  workflowLogs WorkflowLog[]
295
300
  canvasDocuments CanvasDocument[]
301
+ fileUsages UserFileConversation[]
296
302
 
297
303
  @@index([userId])
298
304
  @@index([createdAt])
@@ -325,7 +331,6 @@ model Answer {
325
331
  WorkflowLog WorkflowLog[]
326
332
  files MessageFile[]
327
333
  canvasDocumentId String? // No FK constraint - flexible document management
328
-
329
334
  @@index([conversationId])
330
335
  @@index([messageId])
331
336
  @@index([role])
@@ -890,7 +895,8 @@ enum FolderItemType {
890
895
  CONVERSATION
891
896
  CANVAS_DOCUMENT
892
897
  REFERENCE
893
- ATTACHMENT
898
+ ATTACHMENT // deprecated — kept for migration of old data
899
+ USER_FILE
894
900
  }
895
901
 
896
902
  // Folder activity types (for timeline)
@@ -902,10 +908,41 @@ enum FolderActivityType {
902
908
  ITEM_ADDED
903
909
  ITEM_REMOVED
904
910
  ITEM_UPDATED
911
+ ITEM_MOVED
905
912
  SHARE_ADDED
906
913
  SHARE_REMOVED
907
914
  USER_MESSAGE
908
915
  USER_NOTE
916
+ FILE_INDEXED
917
+ FILE_INDEX_ERROR
918
+ }
919
+
920
+ enum UserFileStatus {
921
+ STORED
922
+ QUEUED
923
+ INDEXING
924
+ INDEXED
925
+ ERROR
926
+ DELETED
927
+ }
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
+
935
+ enum IndexingJobStatus {
936
+ QUEUED
937
+ RUNNING
938
+ COMPLETED
939
+ FAILED
940
+ }
941
+
942
+ enum FolderType {
943
+ PERSONAL
944
+ MATTER
945
+ KNOWLEDGE_BASE
909
946
  }
910
947
 
911
948
  // Folder permission levels
@@ -1089,6 +1126,137 @@ enum IngestionStatus {
1089
1126
  ERROR
1090
1127
  }
1091
1128
 
1129
+ model UserFile {
1130
+ id String @id @default(cuid())
1131
+ userId String
1132
+
1133
+ storageKey String @unique
1134
+ storageUrl String?
1135
+ checksumSha256 String
1136
+
1137
+ fileName String
1138
+ fileType String
1139
+ fileSize Int
1140
+ pageCount Int?
1141
+ language String? @default("sk")
1142
+
1143
+ status UserFileStatus @default(STORED)
1144
+
1145
+ docType String?
1146
+ legalArea String?
1147
+ summary String?
1148
+ extractedData Json?
1149
+ references String[] @default([])
1150
+ chunkCount Int?
1151
+ qdrantDocId String? @unique
1152
+ indexingCost Float?
1153
+ indexedAt DateTime?
1154
+ indexError String?
1155
+
1156
+ tags String[] @default([])
1157
+
1158
+ parentFileId String?
1159
+ versionNumber Int @default(1)
1160
+
1161
+ uploadSource UserFileUploadSource @default(STORAGE)
1162
+ uploadContextId String? // polymorphic: folderId | conversationId | null
1163
+
1164
+ createdAt DateTime @default(now())
1165
+ updatedAt DateTime @updatedAt
1166
+ deletedAt DateTime?
1167
+
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[]
1174
+
1175
+ @@index([userId])
1176
+ @@index([status])
1177
+ @@index([userId, status])
1178
+ @@index([userId, deletedAt])
1179
+ @@index([qdrantDocId])
1180
+ @@index([uploadSource])
1181
+ @@index([uploadContextId])
1182
+ @@index([checksumSha256])
1183
+ }
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
+
1199
+ model FileIndexingJob {
1200
+ id String @id @default(cuid())
1201
+ fileId String
1202
+ userId String
1203
+ status IndexingJobStatus @default(QUEUED)
1204
+ attempts Int @default(0)
1205
+ maxAttempts Int @default(3)
1206
+ errorMsg String?
1207
+ startedAt DateTime?
1208
+ finishedAt DateTime?
1209
+ createdAt DateTime @default(now())
1210
+
1211
+ file UserFile @relation(fields: [fileId], references: [id], onDelete: Cascade)
1212
+
1213
+ @@index([fileId])
1214
+ @@index([userId])
1215
+ @@index([status])
1216
+ @@index([createdAt])
1217
+ }
1218
+
1219
+ model FileDeadline {
1220
+ id String @id @default(cuid())
1221
+ fileId String
1222
+ userId String
1223
+ label String
1224
+ deadlineAt DateTime
1225
+ notifyAt DateTime?
1226
+ isNotified Boolean @default(false)
1227
+ isDismissed Boolean @default(false)
1228
+ sourceSection String?
1229
+ sourcePage Int?
1230
+ createdAt DateTime @default(now())
1231
+
1232
+ file UserFile @relation(fields: [fileId], references: [id], onDelete: Cascade)
1233
+
1234
+ @@index([fileId])
1235
+ @@index([userId])
1236
+ @@index([deadlineAt])
1237
+ @@index([notifyAt, isNotified])
1238
+ @@index([userId, isDismissed])
1239
+ }
1240
+
1241
+ model FileReviewTable {
1242
+ id String @id @default(cuid())
1243
+ userId String
1244
+ folderId String?
1245
+ name String
1246
+ columns Json
1247
+ fileIds String[] @default([])
1248
+ results Json?
1249
+ status String @default("draft")
1250
+ createdAt DateTime @default(now())
1251
+ updatedAt DateTime @updatedAt
1252
+
1253
+ user User @relation("UserReviewTables", fields: [userId], references: [id], onDelete: Cascade)
1254
+
1255
+ @@index([userId])
1256
+ @@index([folderId])
1257
+ @@index([status])
1258
+ }
1259
+
1092
1260
  enum LifecycleStage {
1093
1261
  REGISTERED
1094
1262
  ACTIVATED
@@ -1237,6 +1405,9 @@ model Folder {
1237
1405
  path String @default("/") // Materialized path: "/parentId/grandparentId/..."
1238
1406
  depth Int @default(0)
1239
1407
 
1408
+ // Folder type
1409
+ folderType FolderType @default(PERSONAL)
1410
+
1240
1411
  // Metadata
1241
1412
  sortOrder Int @default(0)
1242
1413
  isArchived Boolean @default(false)
@@ -0,0 +1,194 @@
1
+ -- CreateEnum
2
+ CREATE TYPE "UserFileStatus" AS ENUM ('STORED', 'QUEUED', 'INDEXING', 'INDEXED', 'ERROR', 'DELETED');
3
+
4
+ -- CreateEnum
5
+ CREATE TYPE "IndexingJobStatus" AS ENUM ('QUEUED', 'RUNNING', 'COMPLETED', 'FAILED');
6
+
7
+ -- CreateEnum
8
+ CREATE TYPE "FolderType" AS ENUM ('PERSONAL', 'MATTER', 'KNOWLEDGE_BASE');
9
+
10
+ -- AlterEnum
11
+ -- This migration adds more than one value to an enum.
12
+ -- With PostgreSQL versions 11 and earlier, this is not possible
13
+ -- in a single migration. This can be worked around by creating
14
+ -- multiple migrations, each migration adding only one value to
15
+ -- the enum.
16
+
17
+
18
+ ALTER TYPE "FolderActivityType" ADD VALUE 'ITEM_MOVED';
19
+ ALTER TYPE "FolderActivityType" ADD VALUE 'FILE_INDEXED';
20
+ ALTER TYPE "FolderActivityType" ADD VALUE 'FILE_INDEX_ERROR';
21
+
22
+ -- AlterEnum
23
+ ALTER TYPE "FolderItemType" ADD VALUE 'USER_FILE';
24
+
25
+ -- AlterTable
26
+ ALTER TABLE "Folder" ADD COLUMN "folderType" "FolderType" NOT NULL DEFAULT 'PERSONAL';
27
+
28
+ -- AlterTable
29
+ ALTER TABLE "User" ADD COLUMN "filesCount" INTEGER NOT NULL DEFAULT 0,
30
+ ADD COLUMN "filesTotalBytes" BIGINT NOT NULL DEFAULT 0;
31
+
32
+ -- CreateTable
33
+ CREATE TABLE "UserFile" (
34
+ "id" TEXT NOT NULL,
35
+ "userId" TEXT NOT NULL,
36
+ "storageKey" TEXT NOT NULL,
37
+ "storageUrl" TEXT,
38
+ "checksumSha256" TEXT NOT NULL,
39
+ "fileName" TEXT NOT NULL,
40
+ "fileType" TEXT NOT NULL,
41
+ "fileSize" INTEGER NOT NULL,
42
+ "pageCount" INTEGER,
43
+ "language" TEXT DEFAULT 'sk',
44
+ "status" "UserFileStatus" NOT NULL DEFAULT 'STORED',
45
+ "docType" TEXT,
46
+ "legalArea" TEXT,
47
+ "summary" TEXT,
48
+ "extractedData" JSONB,
49
+ "references" TEXT[] DEFAULT ARRAY[]::TEXT[],
50
+ "chunkCount" INTEGER,
51
+ "qdrantDocId" TEXT,
52
+ "indexingCost" DOUBLE PRECISION,
53
+ "indexedAt" TIMESTAMP(3),
54
+ "indexError" TEXT,
55
+ "tags" TEXT[] DEFAULT ARRAY[]::TEXT[],
56
+ "parentFileId" TEXT,
57
+ "versionNumber" INTEGER NOT NULL DEFAULT 1,
58
+ "answerId" TEXT,
59
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
60
+ "updatedAt" TIMESTAMP(3) NOT NULL,
61
+ "deletedAt" TIMESTAMP(3),
62
+
63
+ CONSTRAINT "UserFile_pkey" PRIMARY KEY ("id")
64
+ );
65
+
66
+ -- CreateTable
67
+ CREATE TABLE "FileIndexingJob" (
68
+ "id" TEXT NOT NULL,
69
+ "fileId" TEXT NOT NULL,
70
+ "userId" TEXT NOT NULL,
71
+ "status" "IndexingJobStatus" NOT NULL DEFAULT 'QUEUED',
72
+ "attempts" INTEGER NOT NULL DEFAULT 0,
73
+ "maxAttempts" INTEGER NOT NULL DEFAULT 3,
74
+ "errorMsg" TEXT,
75
+ "startedAt" TIMESTAMP(3),
76
+ "finishedAt" TIMESTAMP(3),
77
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
78
+
79
+ CONSTRAINT "FileIndexingJob_pkey" PRIMARY KEY ("id")
80
+ );
81
+
82
+ -- CreateTable
83
+ CREATE TABLE "FileDeadline" (
84
+ "id" TEXT NOT NULL,
85
+ "fileId" TEXT NOT NULL,
86
+ "userId" TEXT NOT NULL,
87
+ "label" TEXT NOT NULL,
88
+ "deadlineAt" TIMESTAMP(3) NOT NULL,
89
+ "notifyAt" TIMESTAMP(3),
90
+ "isNotified" BOOLEAN NOT NULL DEFAULT false,
91
+ "isDismissed" BOOLEAN NOT NULL DEFAULT false,
92
+ "sourceSection" TEXT,
93
+ "sourcePage" INTEGER,
94
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
95
+
96
+ CONSTRAINT "FileDeadline_pkey" PRIMARY KEY ("id")
97
+ );
98
+
99
+ -- CreateTable
100
+ CREATE TABLE "FileReviewTable" (
101
+ "id" TEXT NOT NULL,
102
+ "userId" TEXT NOT NULL,
103
+ "folderId" TEXT,
104
+ "name" TEXT NOT NULL,
105
+ "columns" JSONB NOT NULL,
106
+ "fileIds" TEXT[] DEFAULT ARRAY[]::TEXT[],
107
+ "results" JSONB,
108
+ "status" TEXT NOT NULL DEFAULT 'draft',
109
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
110
+ "updatedAt" TIMESTAMP(3) NOT NULL,
111
+
112
+ CONSTRAINT "FileReviewTable_pkey" PRIMARY KEY ("id")
113
+ );
114
+
115
+ -- CreateIndex
116
+ CREATE UNIQUE INDEX "UserFile_storageKey_key" ON "UserFile"("storageKey");
117
+
118
+ -- CreateIndex
119
+ CREATE UNIQUE INDEX "UserFile_qdrantDocId_key" ON "UserFile"("qdrantDocId");
120
+
121
+ -- CreateIndex
122
+ CREATE INDEX "UserFile_userId_idx" ON "UserFile"("userId");
123
+
124
+ -- CreateIndex
125
+ CREATE INDEX "UserFile_status_idx" ON "UserFile"("status");
126
+
127
+ -- CreateIndex
128
+ CREATE INDEX "UserFile_userId_status_idx" ON "UserFile"("userId", "status");
129
+
130
+ -- CreateIndex
131
+ CREATE INDEX "UserFile_userId_deletedAt_idx" ON "UserFile"("userId", "deletedAt");
132
+
133
+ -- CreateIndex
134
+ CREATE INDEX "UserFile_qdrantDocId_idx" ON "UserFile"("qdrantDocId");
135
+
136
+ -- CreateIndex
137
+ CREATE INDEX "UserFile_answerId_idx" ON "UserFile"("answerId");
138
+
139
+ -- CreateIndex
140
+ CREATE INDEX "UserFile_checksumSha256_idx" ON "UserFile"("checksumSha256");
141
+
142
+ -- CreateIndex
143
+ CREATE INDEX "FileIndexingJob_fileId_idx" ON "FileIndexingJob"("fileId");
144
+
145
+ -- CreateIndex
146
+ CREATE INDEX "FileIndexingJob_userId_idx" ON "FileIndexingJob"("userId");
147
+
148
+ -- CreateIndex
149
+ CREATE INDEX "FileIndexingJob_status_idx" ON "FileIndexingJob"("status");
150
+
151
+ -- CreateIndex
152
+ CREATE INDEX "FileIndexingJob_createdAt_idx" ON "FileIndexingJob"("createdAt");
153
+
154
+ -- CreateIndex
155
+ CREATE INDEX "FileDeadline_fileId_idx" ON "FileDeadline"("fileId");
156
+
157
+ -- CreateIndex
158
+ CREATE INDEX "FileDeadline_userId_idx" ON "FileDeadline"("userId");
159
+
160
+ -- CreateIndex
161
+ CREATE INDEX "FileDeadline_deadlineAt_idx" ON "FileDeadline"("deadlineAt");
162
+
163
+ -- CreateIndex
164
+ CREATE INDEX "FileDeadline_notifyAt_isNotified_idx" ON "FileDeadline"("notifyAt", "isNotified");
165
+
166
+ -- CreateIndex
167
+ CREATE INDEX "FileDeadline_userId_isDismissed_idx" ON "FileDeadline"("userId", "isDismissed");
168
+
169
+ -- CreateIndex
170
+ CREATE INDEX "FileReviewTable_userId_idx" ON "FileReviewTable"("userId");
171
+
172
+ -- CreateIndex
173
+ CREATE INDEX "FileReviewTable_folderId_idx" ON "FileReviewTable"("folderId");
174
+
175
+ -- CreateIndex
176
+ CREATE INDEX "FileReviewTable_status_idx" ON "FileReviewTable"("status");
177
+
178
+ -- AddForeignKey
179
+ ALTER TABLE "UserFile" ADD CONSTRAINT "UserFile_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
180
+
181
+ -- AddForeignKey
182
+ ALTER TABLE "UserFile" ADD CONSTRAINT "UserFile_answerId_fkey" FOREIGN KEY ("answerId") REFERENCES "Answer"("id") ON DELETE SET NULL ON UPDATE CASCADE;
183
+
184
+ -- AddForeignKey
185
+ ALTER TABLE "UserFile" ADD CONSTRAINT "UserFile_parentFileId_fkey" FOREIGN KEY ("parentFileId") REFERENCES "UserFile"("id") ON DELETE SET NULL ON UPDATE CASCADE;
186
+
187
+ -- AddForeignKey
188
+ ALTER TABLE "FileIndexingJob" ADD CONSTRAINT "FileIndexingJob_fileId_fkey" FOREIGN KEY ("fileId") REFERENCES "UserFile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
189
+
190
+ -- AddForeignKey
191
+ ALTER TABLE "FileDeadline" ADD CONSTRAINT "FileDeadline_fileId_fkey" FOREIGN KEY ("fileId") REFERENCES "UserFile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
192
+
193
+ -- AddForeignKey
194
+ ALTER TABLE "FileReviewTable" ADD CONSTRAINT "FileReviewTable_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -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;