generator client { provider = "prisma-client-js" previewFeatures = [] binaryTargets = ["native", "linux-musl-openssl-3.0.x"] engineType = "library" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model User { id String @id @default(uuid()) email String @unique username String @unique password String role Role @default(USER) isActive Boolean @default(false) canDownload Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt department String @default("") dingtalkUserId String? loginType String @default("normal") realName String? phone String? avatar String? managedDepartment String? isSuperAdmin Boolean @default(false) departmentId String? employmentStatus String? @default("active") resignationDate DateTime? transferDate DateTime? transferToDeptId String? employmentNote String? statusChangedBy String? statusChangedAt DateTime? status String @default("pending") lastLoginAt DateTime? lastLoginIp String? loginCount Int @default(0) archivedAt DateTime? managedDepartments Department[] @relation("DepartmentManager") downloadLogs MaterialDownloadLog[] favorites MaterialFavorite[] likes MaterialLike[] materialLogs MaterialLog[] materialTransfersFrom MaterialTransfer[] @relation("MaterialTransferFromUser") materialTransfersTo MaterialTransfer[] @relation("MaterialTransferToUser") materialTransfersAsOperator MaterialTransfer[] @relation("MaterialTransferOperator") materials Material[] departmentRef Department? @relation("UserDepartment", fields: [departmentId], references: [id]) transferToDept Department? @relation("UserTransferDepartment", fields: [transferToDeptId], references: [id]) @@index([status]) @@index([archivedAt]) @@index([departmentId]) @@index([employmentStatus]) @@index([transferToDeptId]) @@map("users") } model Material { id String @id @default(uuid()) previewUrl String productModel String reportTitle String? @map("report_title") categoryName String sceneName String materialType String @default("3DMAX") renderer String @default("CR") authorName String zipFileName String @default("") zipFilePath String @default("") zipFileSize BigInt @default(0) downloadCount Int @default(0) likeCount Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt userId String displayImages String[] @default([]) platformName String @default("") uploadId String? videoSourceUrl String? videoPreview540Url String? videoPreviewClipUrl String? videoCoverUrl String? videoDuration Int? videoProcessingStatus String? transcodeLastError String? @map("transcodelasterror") transcodeAttempts Int? @map("transcodeattempts") deletedAt DateTime? productCategoryName String @default("") originalOwnerId String? transferredAt DateTime? transferredBy String? transferNote String? taskNo String? @map("task_no") taskStatus String? @map("task_status") taskFetchedAt DateTime? @map("task_fetched_at") isFullSet Boolean @default(false) @map("is_full_set") isAiGenerated Boolean @default(false) @map("is_ai_generated") taskDetailSourceType String? @map("task_detail_source_type") assets MaterialAsset[] downloadLogs MaterialDownloadLog[] favorites MaterialFavorite[] likes MaterialLike[] logs MaterialLog[] skus MaterialSku[] transfers MaterialTransfer[] transcodeProgresses VideoTranscodeProgress[] @relation("MaterialTranscodeProgress") user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@index([createdAt]) @@index([categoryName]) @@index([sceneName]) @@index([platformName]) @@index([productCategoryName]) @@index([materialType]) @@index([downloadCount]) @@index([likeCount]) @@index([deletedAt]) @@index([originalOwnerId]) @@index([transferredAt]) @@index([taskNo]) @@index([taskStatus]) @@index([isFullSet]) @@index([productModel]) @@index([reportTitle]) @@index([authorName]) @@map("materials") } model MaterialLike { id String @id @default(uuid()) materialId String userId String createdAt DateTime @default(now()) material Material @relation(fields: [materialId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([materialId, userId]) @@index([materialId]) @@index([userId]) @@map("material_likes") } model MaterialFavorite { id String @id @default(uuid()) materialId String userId String createdAt DateTime @default(now()) material Material @relation(fields: [materialId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([materialId, userId]) @@index([materialId]) @@index([userId]) @@map("material_favorites") } model MaterialDownloadLog { id String @id @default(uuid()) materialId String userId String downloadedAt DateTime @default(now()) material Material @relation(fields: [materialId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([materialId]) @@index([userId]) @@index([downloadedAt]) @@index([materialId, userId, downloadedAt]) @@map("material_download_logs") } model MaterialLog { id String @id @default(uuid()) materialId String userId String action String changes String? timestamp DateTime @default(now()) material Material @relation(fields: [materialId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([materialId]) @@index([userId]) @@index([timestamp]) @@map("material_logs") } model MaterialSku { id String @id @default(uuid()) materialId String @map("material_id") skuName String @map("sku_name") filePath String @map("file_path") fileSize BigInt @default(0) @map("file_size") sortOrder Int @default(0) @map("sort_order") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") fileName String? @map("file_name") previewUrl String? @map("preview_url") deletedAt DateTime? @map("deleted_at") whiteBackgroundSourceType String? @map("white_background_source_type") whiteBackgroundUploadedBy String? @map("white_background_uploaded_by") whiteBackgroundUploadedAt DateTime? @map("white_background_uploaded_at") material Material @relation(fields: [materialId], references: [id], onDelete: Cascade) @@index([materialId]) @@index([skuName, deletedAt]) @@index([sortOrder]) @@index([deletedAt]) @@index([whiteBackgroundSourceType]) @@index([whiteBackgroundUploadedBy]) @@index([whiteBackgroundUploadedAt]) @@map("material_skus") } model ProductCategory { id String @id @default(uuid()) name String @unique createdAt DateTime @default(now()) @@map("product_categories") } model Category { id String @id @default(uuid()) name String @unique createdAt DateTime @default(now()) @@map("categories") } model Scene { id String @id @default(uuid()) name String @unique createdAt DateTime @default(now()) @@map("scenes") } model Platform { id String @id @default(uuid()) name String @unique createdAt DateTime @default(now()) @@map("platforms") } model SystemSettings { id String @id @default(uuid()) headerBgColor String @default("#1f2937") siteName String @default("由壹点3D素材") updatedAt DateTime @updatedAt createdAt DateTime @default(now()) headerLogoUrl String @default("http://s3.1080p.hk/shuzhou/2025/05/18/8ebadf0a7cc34eaea00e8619b8efb827.png") loginLogoUrl String @default("http://s3.1080p.hk/shuzhou/2025/05/18/8ebadf0a7cc34eaea00e8619b8efb827.png") s3AccessKey String @default("") s3Bucket String @default("") s3Endpoint String @default("") s3PublicUrl String @default("") s3Region String @default("us-east-1") s3SecretKey String @default("") maintenanceEnabled Boolean @default(false) @map("maintenance_enabled") maintenanceMessage String? @map("maintenance_message") maintenanceStartTime DateTime? @map("maintenance_start_time") maintenanceEndTime DateTime? @map("maintenance_end_time") @@map("system_settings") } model Department { id String @id @default(uuid()) name String @unique createdAt DateTime @default(now()) parentId String? level Int @default(1) status String @default("active") managerId String? code String? @unique description String? sortOrder Int @default(0) updatedAt DateTime @updatedAt manager User? @relation("DepartmentManager", fields: [managerId], references: [id]) parent Department? @relation("DepartmentHierarchy", fields: [parentId], references: [id]) children Department[] @relation("DepartmentHierarchy") users User[] @relation("UserDepartment") transferredUsers User[] @relation("UserTransferDepartment") @@index([parentId]) @@index([status]) @@index([level]) @@index([managerId]) @@map("departments") } model Danmaku { id String @id @default(uuid()) content String username String userId String createdAt DateTime @default(now()) @@index([createdAt]) @@map("danmakus") } model DepartmentMaterialPermission { id String @id @default(uuid()) department String materialType String canView Boolean @default(false) canDownload Boolean @default(false) canShare Boolean @default(true) linkedToDepartment String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt canDownloadSource Boolean @default(false) @map("can_download_source") @@unique([department, materialType]) @@index([department]) @@index([materialType]) @@index([linkedToDepartment]) @@map("department_material_permissions") } model MaterialTransfer { id String @id @default(uuid()) materialId String fromUserId String toUserId String transferredBy String transferNote String? transferredAt DateTime @default(now()) fromUser User @relation("MaterialTransferFromUser", fields: [fromUserId], references: [id]) material Material @relation(fields: [materialId], references: [id], onDelete: Cascade) toUser User @relation("MaterialTransferToUser", fields: [toUserId], references: [id]) operator User @relation("MaterialTransferOperator", fields: [transferredBy], references: [id]) @@index([materialId]) @@index([fromUserId]) @@index([toUserId]) @@index([transferredAt]) @@map("material_transfers") } model MaterialAsset { id String @id @default(uuid()) materialId String @map("material_id") assetType String @map("asset_type") fileUrl String @map("file_url") fileName String? @map("file_name") fileSize BigInt @default(0) @map("file_size") sortOrder Int @default(0) @map("sort_order") skuCode String? @map("sku_code") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") material Material @relation(fields: [materialId], references: [id], onDelete: Cascade) barcodes MaterialAssetBarcode[] @@index([materialId]) @@index([assetType]) @@index([sortOrder]) @@map("material_assets") } model MaterialAssetBarcode { id String @id @default(uuid()) assetId String @map("asset_id") barcode String createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") asset MaterialAsset @relation(fields: [assetId], references: [id], onDelete: Cascade) @@unique([assetId, barcode]) @@index([barcode]) @@index([assetId]) @@map("material_asset_barcodes") } model ApiKey { id String @id @default(uuid()) name String key String @unique isActive Boolean @default(true) @map("is_active") createdBy String @map("created_by") lastUsedAt DateTime? @map("last_used_at") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") callLogs ApiCallLog[] externalMaterialImportJobs ExternalMaterialImportJob[] @@index([key]) @@index([isActive]) @@map("api_keys") } model ApiCallLog { id String @id @default(uuid()) apiKeyId String @map("api_key_id") endpoint String method String taskNo String? @map("task_no") queryType String? @map("query_type") queryValue String? @map("query_value") statusCode Int @map("status_code") duration Int ipAddress String? @map("ip_address") userAgent String? @map("user_agent") createdAt DateTime @default(now()) @map("created_at") apiKey ApiKey @relation(fields: [apiKeyId], references: [id], onDelete: Cascade) @@index([apiKeyId]) @@index([taskNo]) @@index([queryType]) @@index([queryValue]) @@index([createdAt]) @@map("api_call_logs") } model ExternalMaterialImportJob { id String @id @default(uuid()) apiKeyId String @map("api_key_id") clientRequestId String @map("client_request_id") materialType String @map("material_type") taskNo String @map("task_no") status String resolvedUserId String? @map("resolved_user_id") requestPayload Json @map("request_payload") submissionSnapshot Json @map("submission_snapshot") resultMaterialId String? @map("result_material_id") errorCode String? @map("error_code") errorMessage String? @map("error_message") completedAt DateTime? @map("completed_at") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") apiKey ApiKey @relation(fields: [apiKeyId], references: [id], onDelete: Cascade) @@unique([apiKeyId, clientRequestId]) @@index([taskNo, status]) @@index([status]) @@index([createdAt]) @@map("external_material_import_jobs") } model VideoTranscodeProgress { id String @id @default(uuid()) materialId String @map("material_id") stage String progress Int @default(0) status String @default("waiting") @map("status") priority Int @default(0) startedAt DateTime @default(now()) @map("started_at") completedAt DateTime? @map("completed_at") errorMessage String? @map("error_message") retryCount Int @default(0) @map("retry_count") lastHeartbeat DateTime? @map("last_heartbeat") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") material Material @relation("MaterialTranscodeProgress", fields: [materialId], references: [id], onDelete: Cascade) @@unique([materialId, stage]) @@index([status]) @@index([priority, status]) @@index([materialId]) @@index([lastHeartbeat]) @@map("video_transcode_progresses") } enum Role { USER ADMIN DEPT_ADMIN SYSTEM_ADMIN }