init
This commit is contained in:
231
server/prisma/migrations/20260326034442_init/migration.sql
Normal file
231
server/prisma/migrations/20260326034442_init/migration.sql
Normal file
@@ -0,0 +1,231 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "tools" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"category_id" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"rating" REAL NOT NULL DEFAULT 0,
|
||||
"download_count" INTEGER NOT NULL DEFAULT 0,
|
||||
"open_count" INTEGER NOT NULL DEFAULT 0,
|
||||
"access_mode" TEXT NOT NULL DEFAULT 'download',
|
||||
"open_url" TEXT,
|
||||
"open_in_new_tab" BOOLEAN NOT NULL DEFAULT true,
|
||||
"latest_artifact_id" TEXT,
|
||||
"status" TEXT NOT NULL DEFAULT 'draft',
|
||||
"updated_at" TEXT NOT NULL,
|
||||
"is_deleted" BOOLEAN NOT NULL DEFAULT false,
|
||||
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"modified_at" DATETIME NOT NULL,
|
||||
CONSTRAINT "tools_category_id_fkey" FOREIGN KEY ("category_id") REFERENCES "categories" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
CONSTRAINT "tools_latest_artifact_id_fkey" FOREIGN KEY ("latest_artifact_id") REFERENCES "tool_artifacts" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "tool_artifacts" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"tool_id" TEXT NOT NULL,
|
||||
"version" TEXT NOT NULL,
|
||||
"file_name" TEXT NOT NULL,
|
||||
"file_size_bytes" INTEGER NOT NULL,
|
||||
"sha256" TEXT NOT NULL,
|
||||
"mime_type" TEXT,
|
||||
"gitlab_project_id" INTEGER NOT NULL,
|
||||
"gitlab_package_name" TEXT NOT NULL,
|
||||
"gitlab_package_version" TEXT NOT NULL,
|
||||
"gitlab_file_path" TEXT NOT NULL,
|
||||
"status" TEXT NOT NULL DEFAULT 'active',
|
||||
"release_notes" TEXT,
|
||||
"uploaded_by" TEXT,
|
||||
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "tool_artifacts_tool_id_fkey" FOREIGN KEY ("tool_id") REFERENCES "tools" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
CONSTRAINT "tool_artifacts_uploaded_by_fkey" FOREIGN KEY ("uploaded_by") REFERENCES "admin_users" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "categories" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"sort_order" INTEGER NOT NULL DEFAULT 100,
|
||||
"is_deleted" BOOLEAN NOT NULL DEFAULT false
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "tags" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"is_deleted" BOOLEAN NOT NULL DEFAULT false
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "tool_tags" (
|
||||
"tool_id" TEXT NOT NULL,
|
||||
"tag_id" TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY ("tool_id", "tag_id"),
|
||||
CONSTRAINT "tool_tags_tool_id_fkey" FOREIGN KEY ("tool_id") REFERENCES "tools" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "tool_tags_tag_id_fkey" FOREIGN KEY ("tag_id") REFERENCES "tags" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "tool_features" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"tool_id" TEXT NOT NULL,
|
||||
"feature_text" TEXT NOT NULL,
|
||||
"sort_order" INTEGER NOT NULL DEFAULT 100,
|
||||
CONSTRAINT "tool_features_tool_id_fkey" FOREIGN KEY ("tool_id") REFERENCES "tools" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "hot_keywords" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"keyword" TEXT NOT NULL,
|
||||
"sort_order" INTEGER NOT NULL DEFAULT 100,
|
||||
"is_active" BOOLEAN NOT NULL DEFAULT true
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "download_tickets" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"ticket" TEXT NOT NULL,
|
||||
"tool_id" TEXT NOT NULL,
|
||||
"artifact_id" TEXT NOT NULL,
|
||||
"channel" TEXT,
|
||||
"client_version" TEXT,
|
||||
"request_ip" TEXT,
|
||||
"expires_at" DATETIME NOT NULL,
|
||||
"consumed_at" DATETIME,
|
||||
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "download_tickets_tool_id_fkey" FOREIGN KEY ("tool_id") REFERENCES "tools" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
CONSTRAINT "download_tickets_artifact_id_fkey" FOREIGN KEY ("artifact_id") REFERENCES "tool_artifacts" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "download_records" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"tool_id" TEXT NOT NULL,
|
||||
"artifact_id" TEXT NOT NULL,
|
||||
"ticket" TEXT,
|
||||
"downloaded_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"client_ip" TEXT,
|
||||
"user_agent" TEXT,
|
||||
"channel" TEXT,
|
||||
"client_version" TEXT,
|
||||
"status" TEXT NOT NULL DEFAULT 'success',
|
||||
"error_message" TEXT,
|
||||
CONSTRAINT "download_records_tool_id_fkey" FOREIGN KEY ("tool_id") REFERENCES "tools" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
CONSTRAINT "download_records_artifact_id_fkey" FOREIGN KEY ("artifact_id") REFERENCES "tool_artifacts" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "open_records" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"tool_id" TEXT NOT NULL,
|
||||
"opened_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"client_ip" TEXT,
|
||||
"user_agent" TEXT,
|
||||
"channel" TEXT,
|
||||
"client_version" TEXT,
|
||||
"referer" TEXT,
|
||||
CONSTRAINT "open_records_tool_id_fkey" FOREIGN KEY ("tool_id") REFERENCES "tools" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "admin_users" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"username" TEXT NOT NULL,
|
||||
"password_hash" TEXT NOT NULL,
|
||||
"display_name" TEXT,
|
||||
"status" TEXT NOT NULL DEFAULT 'active',
|
||||
"last_login_at" DATETIME,
|
||||
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"modified_at" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "admin_audit_logs" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"admin_user_id" TEXT,
|
||||
"action" TEXT NOT NULL,
|
||||
"resource_type" TEXT NOT NULL,
|
||||
"resource_id" TEXT,
|
||||
"request_method" TEXT NOT NULL,
|
||||
"request_path" TEXT NOT NULL,
|
||||
"request_body" TEXT,
|
||||
"ip" TEXT,
|
||||
"user_agent" TEXT,
|
||||
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "admin_audit_logs_admin_user_id_fkey" FOREIGN KEY ("admin_user_id") REFERENCES "admin_users" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "tools_slug_key" ON "tools"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_tools_category_id" ON "tools"("category_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_tools_status" ON "tools"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_tools_access_mode" ON "tools"("access_mode");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_tools_download_count" ON "tools"("download_count");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_tools_open_count" ON "tools"("open_count");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_tools_updated_at" ON "tools"("updated_at");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_tools_rating" ON "tools"("rating");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_tools_name" ON "tools"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_artifact_tool_id" ON "tool_artifacts"("tool_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_artifact_status" ON "tool_artifacts"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "uk_tool_version" ON "tool_artifacts"("tool_id", "version");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "categories_name_key" ON "categories"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "tags_name_key" ON "tags"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_tool_feature_tool_id" ON "tool_features"("tool_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "hot_keywords_keyword_key" ON "hot_keywords"("keyword");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "download_tickets_ticket_key" ON "download_tickets"("ticket");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_download_tickets_tool_id" ON "download_tickets"("tool_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_download_tickets_expires_at" ON "download_tickets"("expires_at");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_download_records_tool_id" ON "download_records"("tool_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_download_records_artifact_id" ON "download_records"("artifact_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_open_records_tool_id" ON "open_records"("tool_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "admin_users_username_key" ON "admin_users"("username");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_admin_audit_logs_user_id" ON "admin_audit_logs"("admin_user_id");
|
||||
3
server/prisma/migrations/migration_lock.toml
Normal file
3
server/prisma/migrations/migration_lock.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (e.g., Git)
|
||||
provider = "sqlite"
|
||||
246
server/prisma/schema.prisma
Normal file
246
server/prisma/schema.prisma
Normal 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")
|
||||
}
|
||||
152
server/prisma/seed.ts
Normal file
152
server/prisma/seed.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import argon2 from 'argon2';
|
||||
import { PrismaClient, AccessMode, ToolStatus, ArtifactStatus, AdminUserStatus } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
function todayDateString(): string {
|
||||
return new Date().toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const nowDate = todayDateString();
|
||||
|
||||
await prisma.$transaction([
|
||||
prisma.toolTag.deleteMany(),
|
||||
prisma.toolFeature.deleteMany(),
|
||||
prisma.downloadRecord.deleteMany(),
|
||||
prisma.downloadTicket.deleteMany(),
|
||||
prisma.openRecord.deleteMany(),
|
||||
prisma.adminAuditLog.deleteMany(),
|
||||
prisma.toolArtifact.deleteMany(),
|
||||
prisma.tool.deleteMany(),
|
||||
prisma.tag.deleteMany(),
|
||||
prisma.category.deleteMany(),
|
||||
prisma.hotKeyword.deleteMany(),
|
||||
prisma.adminUser.deleteMany(),
|
||||
]);
|
||||
|
||||
await prisma.category.createMany({
|
||||
data: [
|
||||
{ id: 'cat_ai', name: 'AI', sortOrder: 10 },
|
||||
{ id: 'cat_dev', name: 'Developer', sortOrder: 20 },
|
||||
{ id: 'cat_ops', name: 'Operations', sortOrder: 30 },
|
||||
],
|
||||
});
|
||||
|
||||
await prisma.tag.createMany({
|
||||
data: [
|
||||
{ id: 'tag_hot', name: 'Hot' },
|
||||
{ id: 'tag_free', name: 'Free' },
|
||||
{ id: 'tag_official', name: 'Official' },
|
||||
],
|
||||
});
|
||||
|
||||
const webToolId = 'tool_web_001';
|
||||
const downloadToolId = 'tool_dl_001';
|
||||
const artifactId = 'art_001';
|
||||
|
||||
await prisma.tool.create({
|
||||
data: {
|
||||
id: webToolId,
|
||||
name: 'OpenAI Playground',
|
||||
slug: 'openai-playground',
|
||||
categoryId: 'cat_ai',
|
||||
description: 'OpenAI web playground for prompt testing.',
|
||||
rating: 4.8,
|
||||
downloadCount: 0,
|
||||
openCount: 128,
|
||||
accessMode: AccessMode.web,
|
||||
openUrl: 'https://platform.openai.com/playground',
|
||||
openInNewTab: true,
|
||||
status: ToolStatus.published,
|
||||
updatedAt: nowDate,
|
||||
features: {
|
||||
createMany: {
|
||||
data: [
|
||||
{ id: 'feat_web_001', featureText: 'Prompt debugging', sortOrder: 10 },
|
||||
{ id: 'feat_web_002', featureText: 'Model parameter tuning', sortOrder: 20 },
|
||||
],
|
||||
},
|
||||
},
|
||||
tags: {
|
||||
create: [{ tagId: 'tag_hot' }, { tagId: 'tag_official' }],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.tool.create({
|
||||
data: {
|
||||
id: downloadToolId,
|
||||
name: 'ToolsShow Desktop',
|
||||
slug: 'toolsshow-desktop',
|
||||
categoryId: 'cat_dev',
|
||||
description: 'Desktop bundle for local workflows.',
|
||||
rating: 4.6,
|
||||
downloadCount: 52,
|
||||
openCount: 0,
|
||||
accessMode: AccessMode.download,
|
||||
status: ToolStatus.published,
|
||||
updatedAt: nowDate,
|
||||
features: {
|
||||
createMany: {
|
||||
data: [
|
||||
{ id: 'feat_dl_001', featureText: 'Offline usage', sortOrder: 10 },
|
||||
{ id: 'feat_dl_002', featureText: 'Bundled plugins', sortOrder: 20 },
|
||||
],
|
||||
},
|
||||
},
|
||||
tags: {
|
||||
create: [{ tagId: 'tag_free' }],
|
||||
},
|
||||
artifacts: {
|
||||
create: {
|
||||
id: artifactId,
|
||||
version: '1.0.0',
|
||||
fileName: 'toolsshow-desktop-1.0.0.zip',
|
||||
fileSizeBytes: 12_345_678,
|
||||
sha256: 'sample-sha256-not-real',
|
||||
mimeType: 'application/zip',
|
||||
gitlabProjectId: 0,
|
||||
gitlabPackageName: 'toolsshow/toolsshow-desktop',
|
||||
gitlabPackageVersion: '1.0.0',
|
||||
gitlabFilePath: 'storage/toolsshow-desktop-1.0.0.zip',
|
||||
status: ArtifactStatus.active,
|
||||
releaseNotes: 'Initial release',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.tool.update({
|
||||
where: { id: downloadToolId },
|
||||
data: { latestArtifactId: artifactId },
|
||||
});
|
||||
|
||||
await prisma.hotKeyword.createMany({
|
||||
data: [
|
||||
{ id: 'kw_001', keyword: 'agent', sortOrder: 10, isActive: true },
|
||||
{ id: 'kw_002', keyword: 'automation', sortOrder: 20, isActive: true },
|
||||
{ id: 'kw_003', keyword: 'open-source', sortOrder: 30, isActive: true },
|
||||
],
|
||||
});
|
||||
|
||||
const passwordHash = await argon2.hash('admin123456', { type: argon2.argon2id });
|
||||
await prisma.adminUser.create({
|
||||
data: {
|
||||
id: 'u_admin_001',
|
||||
username: 'admin',
|
||||
passwordHash,
|
||||
displayName: 'System Admin',
|
||||
status: AdminUserStatus.active,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
main()
|
||||
.catch(async (error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
Reference in New Issue
Block a user