This commit is contained in:
dlandy
2026-03-27 10:18:26 +08:00
commit 40be11adbf
116 changed files with 26138 additions and 0 deletions

246
server/prisma/schema.prisma Normal file
View File

@@ -0,0 +1,246 @@
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")
}