247 lines
8.3 KiB
Plaintext
247 lines
8.3 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "sqlite"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
enum AccessMode {
|
|
web
|
|
download
|
|
}
|
|
|
|
enum ToolStatus {
|
|
draft
|
|
published
|
|
archived
|
|
}
|
|
|
|
enum ArtifactStatus {
|
|
active
|
|
deprecated
|
|
deleted
|
|
}
|
|
|
|
enum DownloadRecordStatus {
|
|
success
|
|
failed
|
|
}
|
|
|
|
enum AdminUserStatus {
|
|
active
|
|
disabled
|
|
}
|
|
|
|
model Tool {
|
|
id String @id
|
|
name String
|
|
slug String @unique
|
|
categoryId String @map("category_id")
|
|
description String
|
|
rating Float @default(0)
|
|
downloadCount Int @default(0) @map("download_count")
|
|
openCount Int @default(0) @map("open_count")
|
|
accessMode AccessMode @default(download) @map("access_mode")
|
|
openUrl String? @map("open_url")
|
|
openInNewTab Boolean @default(true) @map("open_in_new_tab")
|
|
latestArtifactId String? @map("latest_artifact_id")
|
|
status ToolStatus @default(draft)
|
|
updatedAt String @map("updated_at")
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
modifiedAt DateTime @updatedAt @map("modified_at")
|
|
|
|
category Category @relation(fields: [categoryId], references: [id], onDelete: Restrict)
|
|
latestArtifact ToolArtifact? @relation("ToolLatestArtifact", fields: [latestArtifactId], references: [id], onDelete: SetNull)
|
|
artifacts ToolArtifact[] @relation("ToolArtifacts")
|
|
tags ToolTag[]
|
|
features ToolFeature[]
|
|
downloadTickets DownloadTicket[]
|
|
downloadRecords DownloadRecord[]
|
|
openRecords OpenRecord[]
|
|
|
|
@@index([categoryId], map: "idx_tools_category_id")
|
|
@@index([status], map: "idx_tools_status")
|
|
@@index([accessMode], map: "idx_tools_access_mode")
|
|
@@index([downloadCount], map: "idx_tools_download_count")
|
|
@@index([openCount], map: "idx_tools_open_count")
|
|
@@index([updatedAt], map: "idx_tools_updated_at")
|
|
@@index([rating], map: "idx_tools_rating")
|
|
@@index([name], map: "idx_tools_name")
|
|
@@map("tools")
|
|
}
|
|
|
|
model ToolArtifact {
|
|
id String @id
|
|
toolId String @map("tool_id")
|
|
version String
|
|
fileName String @map("file_name")
|
|
fileSizeBytes Int @map("file_size_bytes")
|
|
sha256 String
|
|
mimeType String? @map("mime_type")
|
|
gitlabProjectId Int @map("gitlab_project_id")
|
|
gitlabPackageName String @map("gitlab_package_name")
|
|
gitlabPackageVersion String @map("gitlab_package_version")
|
|
gitlabFilePath String @map("gitlab_file_path")
|
|
status ArtifactStatus @default(active)
|
|
releaseNotes String? @map("release_notes")
|
|
uploadedBy String? @map("uploaded_by")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
tool Tool @relation("ToolArtifacts", fields: [toolId], references: [id], onDelete: Restrict)
|
|
latestForTool Tool[] @relation("ToolLatestArtifact")
|
|
uploader AdminUser? @relation(fields: [uploadedBy], references: [id], onDelete: SetNull)
|
|
downloadTickets DownloadTicket[]
|
|
downloadRecords DownloadRecord[]
|
|
|
|
@@unique([toolId, version], map: "uk_tool_version")
|
|
@@index([toolId], map: "idx_artifact_tool_id")
|
|
@@index([status], map: "idx_artifact_status")
|
|
@@map("tool_artifacts")
|
|
}
|
|
|
|
model Category {
|
|
id String @id
|
|
name String @unique
|
|
sortOrder Int @default(100) @map("sort_order")
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
tools Tool[]
|
|
|
|
@@map("categories")
|
|
}
|
|
|
|
model Tag {
|
|
id String @id
|
|
name String @unique
|
|
isDeleted Boolean @default(false) @map("is_deleted")
|
|
tools ToolTag[]
|
|
|
|
@@map("tags")
|
|
}
|
|
|
|
model ToolTag {
|
|
toolId String @map("tool_id")
|
|
tagId String @map("tag_id")
|
|
|
|
tool Tool @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
|
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([toolId, tagId])
|
|
@@map("tool_tags")
|
|
}
|
|
|
|
model ToolFeature {
|
|
id String @id
|
|
toolId String @map("tool_id")
|
|
featureText String @map("feature_text")
|
|
sortOrder Int @default(100) @map("sort_order")
|
|
|
|
tool Tool @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([toolId], map: "idx_tool_feature_tool_id")
|
|
@@map("tool_features")
|
|
}
|
|
|
|
model HotKeyword {
|
|
id String @id
|
|
keyword String @unique
|
|
sortOrder Int @default(100) @map("sort_order")
|
|
isActive Boolean @default(true) @map("is_active")
|
|
|
|
@@map("hot_keywords")
|
|
}
|
|
|
|
model DownloadTicket {
|
|
id Int @id @default(autoincrement())
|
|
ticket String @unique
|
|
toolId String @map("tool_id")
|
|
artifactId String @map("artifact_id")
|
|
channel String?
|
|
clientVersion String? @map("client_version")
|
|
requestIp String? @map("request_ip")
|
|
expiresAt DateTime @map("expires_at")
|
|
consumedAt DateTime? @map("consumed_at")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
tool Tool @relation(fields: [toolId], references: [id], onDelete: Restrict)
|
|
artifact ToolArtifact @relation(fields: [artifactId], references: [id], onDelete: Restrict)
|
|
|
|
@@index([toolId], map: "idx_download_tickets_tool_id")
|
|
@@index([expiresAt], map: "idx_download_tickets_expires_at")
|
|
@@map("download_tickets")
|
|
}
|
|
|
|
model DownloadRecord {
|
|
id Int @id @default(autoincrement())
|
|
toolId String @map("tool_id")
|
|
artifactId String @map("artifact_id")
|
|
ticket String?
|
|
downloadedAt DateTime @default(now()) @map("downloaded_at")
|
|
clientIp String? @map("client_ip")
|
|
userAgent String? @map("user_agent")
|
|
channel String?
|
|
clientVersion String? @map("client_version")
|
|
status DownloadRecordStatus @default(success)
|
|
errorMessage String? @map("error_message")
|
|
|
|
tool Tool @relation(fields: [toolId], references: [id], onDelete: Restrict)
|
|
artifact ToolArtifact @relation(fields: [artifactId], references: [id], onDelete: Restrict)
|
|
|
|
@@index([toolId], map: "idx_download_records_tool_id")
|
|
@@index([artifactId], map: "idx_download_records_artifact_id")
|
|
@@map("download_records")
|
|
}
|
|
|
|
model OpenRecord {
|
|
id Int @id @default(autoincrement())
|
|
toolId String @map("tool_id")
|
|
openedAt DateTime @default(now()) @map("opened_at")
|
|
clientIp String? @map("client_ip")
|
|
userAgent String? @map("user_agent")
|
|
channel String?
|
|
clientVersion String? @map("client_version")
|
|
referer String?
|
|
|
|
tool Tool @relation(fields: [toolId], references: [id], onDelete: Restrict)
|
|
|
|
@@index([toolId], map: "idx_open_records_tool_id")
|
|
@@map("open_records")
|
|
}
|
|
|
|
model AdminUser {
|
|
id String @id
|
|
username String @unique
|
|
passwordHash String @map("password_hash")
|
|
displayName String? @map("display_name")
|
|
status AdminUserStatus @default(active)
|
|
lastLoginAt DateTime? @map("last_login_at")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
modifiedAt DateTime @updatedAt @map("modified_at")
|
|
|
|
artifacts ToolArtifact[]
|
|
auditLogs AdminAuditLog[]
|
|
|
|
@@map("admin_users")
|
|
}
|
|
|
|
model AdminAuditLog {
|
|
id Int @id @default(autoincrement())
|
|
adminUserId String? @map("admin_user_id")
|
|
action String
|
|
resourceType String @map("resource_type")
|
|
resourceId String? @map("resource_id")
|
|
requestMethod String @map("request_method")
|
|
requestPath String @map("request_path")
|
|
requestBody String? @map("request_body")
|
|
ip String?
|
|
userAgent String? @map("user_agent")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
adminUser AdminUser? @relation(fields: [adminUserId], references: [id], onDelete: SetNull)
|
|
|
|
@@index([adminUserId], map: "idx_admin_audit_logs_user_id")
|
|
@@map("admin_audit_logs")
|
|
}
|