Files
tools-show/server/prisma/seed.ts

950 lines
27 KiB
TypeScript
Raw Normal View History

2026-03-27 10:18:26 +08:00
import argon2 from 'argon2';
2026-04-11 20:46:55 +08:00
import {
PrismaClient,
AccessMode,
ToolStatus,
ArtifactStatus,
DownloadRecordStatus,
AdminUserStatus,
} from '@prisma/client';
2026-03-27 10:18:26 +08:00
const prisma = new PrismaClient();
2026-04-11 20:46:55 +08:00
type ArtifactSeed = {
id: string;
version: string;
fileName: string;
fileSizeBytes: number;
sha256: string;
mimeType: string;
gitlabProjectId: number;
gitlabPackageName: string;
gitlabPackageVersion: string;
gitlabFilePath: string;
status: ArtifactStatus;
releaseNotes: string;
uploadedBy?: string;
createdAt: Date;
};
type ToolSeed = {
id: string;
name: string;
slug: string;
categoryId: string;
description: string;
rating: number;
downloadCount: number;
openCount: number;
accessMode: AccessMode;
openUrl?: string;
openInNewTab?: boolean;
status: ToolStatus;
createdAt: Date;
updatedAt: string;
features: Array<{
id: string;
featureText: string;
sortOrder: number;
}>;
tagIds: string[];
artifacts?: ArtifactSeed[];
latestArtifactId?: string;
};
const USER_AGENTS = [
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4)',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
'Mozilla/5.0 (X11; Linux x86_64)',
'ToolsShowDesktop/1.1.0',
'curl/8.7.1',
];
function dateOnly(date: Date): string {
return date.toISOString().slice(0, 10);
2026-03-27 10:18:26 +08:00
}
2026-04-11 20:46:55 +08:00
function daysAgo(days: number, hour = 10, minute = 0): Date {
const date = new Date();
date.setHours(hour, minute, 0, 0);
date.setDate(date.getDate() - days);
return date;
}
function makeIp(seed: number): string {
return `10.24.${Math.floor(seed / 200) + 10}.${(seed % 200) + 20}`;
}
function buildOpenRecords(
toolId: string,
dailyCounts: number[],
channel: string,
referer: string,
) {
return dailyCounts.flatMap((count, index) => {
const dayOffset = dailyCounts.length - index - 1;
return Array.from({ length: count }, (_, slot) => ({
toolId,
openedAt: daysAgo(dayOffset, 9 + (slot % 8), (slot * 11) % 60),
clientIp: makeIp(index * 40 + slot),
userAgent: USER_AGENTS[(index + slot) % USER_AGENTS.length],
channel,
clientVersion: channel === 'desktop' ? '1.1.0' : 'web',
referer,
}));
});
}
2026-03-27 10:18:26 +08:00
2026-04-11 20:46:55 +08:00
function buildDownloadRecords(
toolId: string,
artifactId: string,
dailyCounts: number[],
channel: string,
clientVersion: string,
) {
return dailyCounts.flatMap((count, index) => {
const dayOffset = dailyCounts.length - index - 1;
return Array.from({ length: count }, (_, slot) => ({
toolId,
artifactId,
ticket: `ticket_${toolId}_${dayOffset}_${slot}`,
downloadedAt: daysAgo(dayOffset, 8 + (slot % 10), (slot * 7) % 60),
clientIp: makeIp(index * 60 + slot + 300),
userAgent: USER_AGENTS[(index + slot + 1) % USER_AGENTS.length],
channel,
clientVersion,
status: DownloadRecordStatus.success,
errorMessage: null,
}));
});
}
async function createToolWithRelations(tool: ToolSeed) {
await prisma.tool.create({
data: {
id: tool.id,
name: tool.name,
slug: tool.slug,
categoryId: tool.categoryId,
description: tool.description,
rating: tool.rating,
downloadCount: tool.downloadCount,
openCount: tool.openCount,
accessMode: tool.accessMode,
openUrl: tool.openUrl,
openInNewTab: tool.openInNewTab ?? true,
status: tool.status,
createdAt: tool.createdAt,
updatedAt: tool.updatedAt,
features: {
createMany: {
data: tool.features,
},
},
tags: {
create: tool.tagIds.map((tagId) => ({ tagId })),
},
},
});
if (tool.artifacts?.length) {
await prisma.toolArtifact.createMany({
data: tool.artifacts.map((artifact) => ({
...artifact,
toolId: tool.id,
})),
});
}
if (tool.latestArtifactId) {
await prisma.tool.update({
where: { id: tool.id },
data: {
latestArtifactId: tool.latestArtifactId,
updatedAt: tool.updatedAt,
},
});
}
}
async function main() {
2026-03-27 10:18:26 +08:00
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 },
2026-04-11 20:46:55 +08:00
{ id: 'cat_design', name: 'Design', sortOrder: 40 },
{ id: 'cat_productivity', name: 'Productivity', sortOrder: 50 },
2026-03-27 10:18:26 +08:00
],
});
await prisma.tag.createMany({
data: [
{ id: 'tag_hot', name: 'Hot' },
{ id: 'tag_free', name: 'Free' },
{ id: 'tag_official', name: 'Official' },
2026-04-11 20:46:55 +08:00
{ id: 'tag_new', name: 'New' },
{ id: 'tag_team', name: 'Team' },
{ id: 'tag_self_hosted', name: 'Self-hosted' },
{ id: 'tag_enterprise', name: 'Enterprise' },
{ id: 'tag_recommended', name: 'Recommended' },
2026-03-27 10:18:26 +08:00
],
});
2026-04-11 20:46:55 +08:00
const passwordHash = await argon2.hash('admin123456', {
type: argon2.argon2id,
});
await prisma.adminUser.createMany({
data: [
{
id: 'u_admin_001',
username: 'admin',
passwordHash,
displayName: 'System Admin',
status: AdminUserStatus.active,
lastLoginAt: daysAgo(0, 9, 25),
},
{
id: 'u_admin_002',
username: 'ops-admin',
passwordHash,
displayName: 'Operations Admin',
status: AdminUserStatus.active,
lastLoginAt: daysAgo(1, 18, 5),
},
{
id: 'u_admin_003',
username: 'auditor',
passwordHash,
displayName: 'Read Only Auditor',
status: AdminUserStatus.disabled,
lastLoginAt: daysAgo(11, 13, 10),
},
],
});
2026-03-27 10:18:26 +08:00
2026-04-11 20:46:55 +08:00
const tools: ToolSeed[] = [
{
id: 'tool_web_001',
2026-03-27 10:18:26 +08:00
name: 'OpenAI Playground',
slug: 'openai-playground',
categoryId: 'cat_ai',
2026-04-11 20:46:55 +08:00
description:
'OpenAI web playground for prompt iteration, parameter tuning, and quick eval loops.',
rating: 4.9,
2026-03-27 10:18:26 +08:00
downloadCount: 0,
2026-04-11 20:46:55 +08:00
openCount: 642,
2026-03-27 10:18:26 +08:00
accessMode: AccessMode.web,
openUrl: 'https://platform.openai.com/playground',
openInNewTab: true,
status: ToolStatus.published,
2026-04-11 20:46:55 +08:00
createdAt: daysAgo(45, 10, 0),
updatedAt: dateOnly(daysAgo(0)),
features: [
{ id: 'feat_web_001', featureText: 'Prompt debugging', sortOrder: 10 },
{
id: 'feat_web_002',
featureText: 'Model parameter tuning',
sortOrder: 20,
2026-03-27 10:18:26 +08:00
},
2026-04-11 20:46:55 +08:00
{
id: 'feat_web_003',
featureText: 'Quick compare workflow',
sortOrder: 30,
},
],
tagIds: ['tag_hot', 'tag_official', 'tag_recommended'],
2026-03-27 10:18:26 +08:00
},
2026-04-11 20:46:55 +08:00
{
id: 'tool_web_002',
name: 'Claude Artifacts',
slug: 'claude-artifacts',
categoryId: 'cat_ai',
description:
'Web workspace for iterating on prompts, generated UI fragments, and artifact previews.',
rating: 4.7,
downloadCount: 0,
openCount: 438,
accessMode: AccessMode.web,
openUrl: 'https://claude.ai',
openInNewTab: true,
status: ToolStatus.published,
createdAt: daysAgo(31, 11, 0),
updatedAt: dateOnly(daysAgo(1)),
features: [
{ id: 'feat_web_101', featureText: 'Artifact preview', sortOrder: 10 },
{
id: 'feat_web_102',
featureText: 'Long context drafting',
sortOrder: 20,
},
{
id: 'feat_web_103',
featureText: 'Fast iteration loop',
sortOrder: 30,
},
],
tagIds: ['tag_hot', 'tag_new'],
},
{
id: 'tool_web_003',
name: 'Figma AI Board',
slug: 'figma-ai-board',
categoryId: 'cat_design',
description:
'Design board for collecting references, generating layout ideas, and collaborating on concepts.',
rating: 4.5,
downloadCount: 0,
openCount: 271,
accessMode: AccessMode.web,
openUrl: 'https://www.figma.com',
openInNewTab: true,
status: ToolStatus.published,
createdAt: daysAgo(22, 14, 0),
updatedAt: dateOnly(daysAgo(2)),
features: [
{ id: 'feat_web_201', featureText: 'Shared whiteboard', sortOrder: 10 },
{
id: 'feat_web_202',
featureText: 'Prompt-based explorations',
sortOrder: 20,
},
{
id: 'feat_web_203',
featureText: 'Reference clustering',
sortOrder: 30,
},
],
tagIds: ['tag_official', 'tag_team'],
},
{
id: 'tool_web_004',
name: 'Runbook Atlas',
slug: 'runbook-atlas',
categoryId: 'cat_ops',
description:
'Operational runbook viewer with incident links, deployment guides, and on-call context.',
rating: 4.4,
downloadCount: 0,
openCount: 196,
accessMode: AccessMode.web,
openUrl: 'https://atlas.example.internal/runbooks',
openInNewTab: false,
status: ToolStatus.published,
createdAt: daysAgo(19, 9, 0),
updatedAt: dateOnly(daysAgo(3)),
features: [
{
id: 'feat_web_301',
featureText: 'Incident handoff docs',
sortOrder: 10,
},
{
id: 'feat_web_302',
featureText: 'Change checklist templates',
sortOrder: 20,
},
{
id: 'feat_web_303',
featureText: 'Service ownership map',
sortOrder: 30,
},
],
tagIds: ['tag_team', 'tag_self_hosted'],
},
{
id: 'tool_web_005',
name: 'Notion Workflow Hub',
slug: 'notion-workflow-hub',
categoryId: 'cat_productivity',
description:
'Documentation and request-tracking workspace for internal workflow handoffs.',
rating: 4.2,
downloadCount: 0,
openCount: 153,
accessMode: AccessMode.web,
openUrl: 'https://www.notion.so',
openInNewTab: true,
status: ToolStatus.published,
createdAt: daysAgo(12, 13, 30),
updatedAt: dateOnly(daysAgo(1)),
features: [
{
id: 'feat_web_401',
featureText: 'Workflow templates',
sortOrder: 10,
},
{
id: 'feat_web_402',
featureText: 'Knowledge base linking',
sortOrder: 20,
},
{
id: 'feat_web_403',
featureText: 'Review queue boards',
sortOrder: 30,
},
],
tagIds: ['tag_team', 'tag_recommended'],
},
{
id: 'tool_dl_001',
2026-03-27 10:18:26 +08:00
name: 'ToolsShow Desktop',
slug: 'toolsshow-desktop',
categoryId: 'cat_dev',
2026-04-11 20:46:55 +08:00
description:
'Desktop bundle for local workflows, offline browsing, and curated plugin execution.',
rating: 4.8,
downloadCount: 182,
2026-03-27 10:18:26 +08:00
openCount: 0,
accessMode: AccessMode.download,
status: ToolStatus.published,
2026-04-11 20:46:55 +08:00
createdAt: daysAgo(40, 10, 15),
updatedAt: dateOnly(daysAgo(0)),
features: [
{ id: 'feat_dl_001', featureText: 'Offline usage', sortOrder: 10 },
{ id: 'feat_dl_002', featureText: 'Bundled plugins', sortOrder: 20 },
{
id: 'feat_dl_003',
featureText: 'Local workspace sync',
sortOrder: 30,
2026-03-27 10:18:26 +08:00
},
2026-04-11 20:46:55 +08:00
],
tagIds: ['tag_hot', 'tag_free', 'tag_recommended'],
artifacts: [
{
id: 'art_001',
2026-03-27 10:18:26 +08:00
version: '1.0.0',
fileName: 'toolsshow-desktop-1.0.0.zip',
2026-04-11 20:46:55 +08:00
fileSizeBytes: 12345678,
sha256: 'sha256-toolsshow-100',
2026-03-27 10:18:26 +08:00
mimeType: 'application/zip',
2026-04-11 20:46:55 +08:00
gitlabProjectId: 1001,
2026-03-27 10:18:26 +08:00
gitlabPackageName: 'toolsshow/toolsshow-desktop',
gitlabPackageVersion: '1.0.0',
gitlabFilePath: 'storage/toolsshow-desktop-1.0.0.zip',
2026-04-11 20:46:55 +08:00
status: ArtifactStatus.deprecated,
releaseNotes: 'Initial public release with bundled runtime.',
uploadedBy: 'u_admin_001',
createdAt: daysAgo(35, 15, 30),
},
{
id: 'art_002',
version: '1.1.0',
fileName: 'toolsshow-desktop-1.1.0.zip',
fileSizeBytes: 14567890,
sha256: 'sha256-toolsshow-110',
mimeType: 'application/zip',
gitlabProjectId: 1001,
gitlabPackageName: 'toolsshow/toolsshow-desktop',
gitlabPackageVersion: '1.1.0',
gitlabFilePath: 'storage/toolsshow-desktop-1.1.0.zip',
2026-03-27 10:18:26 +08:00
status: ArtifactStatus.active,
2026-04-11 20:46:55 +08:00
releaseNotes: 'Adds plugin auto-update and workspace pinning.',
uploadedBy: 'u_admin_002',
createdAt: daysAgo(8, 16, 45),
2026-03-27 10:18:26 +08:00
},
2026-04-11 20:46:55 +08:00
],
latestArtifactId: 'art_002',
2026-03-27 10:18:26 +08:00
},
2026-04-11 20:46:55 +08:00
{
id: 'tool_dl_002',
name: 'MCP Inspector',
slug: 'mcp-inspector',
categoryId: 'cat_dev',
description:
'Desktop inspector for local MCP servers, request payloads, and connector metadata.',
rating: 4.6,
downloadCount: 134,
openCount: 0,
accessMode: AccessMode.download,
openUrl: 'https://github.com/modelcontextprotocol/inspector/releases',
status: ToolStatus.published,
createdAt: daysAgo(28, 12, 0),
updatedAt: dateOnly(daysAgo(2)),
features: [
{ id: 'feat_dl_101', featureText: 'Connection tracing', sortOrder: 10 },
{ id: 'feat_dl_102', featureText: 'Schema inspection', sortOrder: 20 },
{ id: 'feat_dl_103', featureText: 'Replay requests', sortOrder: 30 },
],
tagIds: ['tag_new', 'tag_recommended'],
artifacts: [
{
id: 'art_101',
version: '0.9.2',
fileName: 'mcp-inspector-0.9.2.dmg',
fileSizeBytes: 67452311,
sha256: 'sha256-mcp-092',
mimeType: 'application/x-apple-diskimage',
gitlabProjectId: 1002,
gitlabPackageName: 'toolsshow/mcp-inspector',
gitlabPackageVersion: '0.9.2',
gitlabFilePath: 'storage/mcp-inspector-0.9.2.dmg',
status: ArtifactStatus.active,
releaseNotes:
'Adds server capability panel and request timeline export.',
uploadedBy: 'u_admin_001',
createdAt: daysAgo(9, 17, 20),
},
],
latestArtifactId: 'art_101',
},
{
id: 'tool_dl_003',
name: 'LogScope Agent',
slug: 'logscope-agent',
categoryId: 'cat_ops',
description:
'Lightweight collector for shipping local logs, traces, and health snapshots to a central view.',
rating: 4.3,
downloadCount: 89,
openCount: 0,
accessMode: AccessMode.download,
status: ToolStatus.published,
createdAt: daysAgo(26, 9, 40),
updatedAt: dateOnly(daysAgo(4)),
features: [
{ id: 'feat_dl_201', featureText: 'Log tail capture', sortOrder: 10 },
{
id: 'feat_dl_202',
featureText: 'Service heartbeat sync',
sortOrder: 20,
},
{
id: 'feat_dl_203',
featureText: 'Remote support bundle',
sortOrder: 30,
},
],
tagIds: ['tag_enterprise', 'tag_self_hosted'],
artifacts: [
{
id: 'art_201',
version: '2.0.0',
fileName: 'logscope-agent-2.0.0.tar.gz',
fileSizeBytes: 28765432,
sha256: 'sha256-logscope-200',
mimeType: 'application/gzip',
gitlabProjectId: 1003,
gitlabPackageName: 'toolsshow/logscope-agent',
gitlabPackageVersion: '2.0.0',
gitlabFilePath: 'storage/logscope-agent-2.0.0.tar.gz',
status: ArtifactStatus.deleted,
releaseNotes: 'Pulled due to startup regression on Linux hosts.',
uploadedBy: 'u_admin_002',
createdAt: daysAgo(21, 14, 0),
},
{
id: 'art_202',
version: '2.1.0',
fileName: 'logscope-agent-2.1.0.tar.gz',
fileSizeBytes: 29876543,
sha256: 'sha256-logscope-210',
mimeType: 'application/gzip',
gitlabProjectId: 1003,
gitlabPackageName: 'toolsshow/logscope-agent',
gitlabPackageVersion: '2.1.0',
gitlabFilePath: 'storage/logscope-agent-2.1.0.tar.gz',
status: ArtifactStatus.active,
releaseNotes:
'Fixes Linux startup regression and improves compression.',
uploadedBy: 'u_admin_002',
createdAt: daysAgo(6, 11, 45),
},
],
latestArtifactId: 'art_202',
},
{
id: 'tool_draft_001',
name: 'Local Agent Kit',
slug: 'local-agent-kit',
categoryId: 'cat_dev',
description:
'Work-in-progress desktop kit for packaging internal prompts, tools, and local runtime configs.',
rating: 0,
downloadCount: 0,
openCount: 0,
accessMode: AccessMode.download,
status: ToolStatus.draft,
createdAt: daysAgo(5, 10, 10),
updatedAt: dateOnly(daysAgo(0)),
features: [
{
id: 'feat_draft_001',
featureText: 'Local prompt packs',
sortOrder: 10,
},
{
id: 'feat_draft_002',
featureText: 'Workspace policies',
sortOrder: 20,
},
],
tagIds: ['tag_new'],
},
{
id: 'tool_archived_001',
name: 'Canvas Pilot',
slug: 'canvas-pilot',
categoryId: 'cat_design',
description:
'Legacy internal design helper kept for historical reference and migration support.',
rating: 3.9,
downloadCount: 14,
openCount: 25,
accessMode: AccessMode.web,
openUrl: 'https://legacy.example.internal/canvas-pilot',
openInNewTab: false,
status: ToolStatus.archived,
createdAt: daysAgo(90, 9, 0),
updatedAt: dateOnly(daysAgo(14)),
features: [
{
id: 'feat_arc_001',
featureText: 'Legacy board import',
sortOrder: 10,
},
{ id: 'feat_arc_002', featureText: 'Snapshot export', sortOrder: 20 },
],
tagIds: ['tag_team'],
},
];
2026-03-27 10:18:26 +08:00
2026-04-11 20:46:55 +08:00
for (const tool of tools) {
await createToolWithRelations(tool);
}
2026-03-27 10:18:26 +08:00
await prisma.hotKeyword.createMany({
data: [
{ id: 'kw_001', keyword: 'agent', sortOrder: 10, isActive: true },
{ id: 'kw_002', keyword: 'automation', sortOrder: 20, isActive: true },
2026-04-11 20:46:55 +08:00
{ id: 'kw_003', keyword: 'mcp', sortOrder: 30, isActive: true },
{ id: 'kw_004', keyword: 'design', sortOrder: 40, isActive: true },
{ id: 'kw_005', keyword: 'workflow', sortOrder: 50, isActive: true },
{ id: 'kw_006', keyword: 'self-hosted', sortOrder: 60, isActive: false },
2026-03-27 10:18:26 +08:00
],
});
2026-04-11 20:46:55 +08:00
await prisma.openRecord.createMany({
data: [
...buildOpenRecords(
'tool_web_001',
[14, 17, 19, 21, 24, 26, 28],
'web',
'/',
),
...buildOpenRecords(
'tool_web_002',
[8, 10, 12, 14, 16, 18, 20],
'web',
'/tools',
),
...buildOpenRecords(
'tool_web_003',
[4, 6, 7, 8, 8, 9, 10],
'web',
'/design',
),
...buildOpenRecords('tool_web_004', [3, 4, 5, 6, 5, 7, 6], 'web', '/ops'),
...buildOpenRecords(
'tool_web_005',
[2, 3, 3, 4, 4, 5, 6],
'web',
'/workspace',
),
...buildOpenRecords(
'tool_dl_002',
[1, 1, 2, 2, 2, 3, 3],
'desktop',
'/admin/tools',
),
],
});
await prisma.downloadRecord.createMany({
data: [
...buildDownloadRecords(
'tool_dl_001',
'art_002',
[3, 4, 5, 6, 8, 9, 10],
'desktop',
'1.1.0',
),
...buildDownloadRecords(
'tool_dl_002',
'art_101',
[2, 2, 3, 4, 4, 5, 6],
'cli',
'0.9.2',
),
...buildDownloadRecords(
'tool_dl_003',
'art_202',
[1, 2, 2, 3, 3, 4, 5],
'agent',
'2.1.0',
),
{
toolId: 'tool_dl_003',
artifactId: 'art_202',
ticket: 'ticket_failed_001',
downloadedAt: daysAgo(2, 23, 15),
clientIp: '10.24.99.40',
userAgent: 'curl/8.7.1',
channel: 'agent',
clientVersion: '2.1.0',
status: DownloadRecordStatus.failed,
errorMessage: 'checksum mismatch',
},
{
toolId: 'tool_dl_001',
artifactId: 'art_002',
ticket: 'ticket_failed_002',
downloadedAt: daysAgo(5, 7, 50),
clientIp: '10.24.99.41',
userAgent: 'ToolsShowDesktop/1.1.0',
channel: 'desktop',
clientVersion: '1.1.0',
status: DownloadRecordStatus.failed,
errorMessage: 'network timeout',
},
],
});
await prisma.downloadTicket.createMany({
data: [
{
ticket: 'seed_ticket_001',
toolId: 'tool_dl_001',
artifactId: 'art_002',
channel: 'desktop',
clientVersion: '1.1.0',
requestIp: '10.24.88.11',
expiresAt: daysAgo(-1, 12, 0),
consumedAt: null,
createdAt: daysAgo(0, 11, 45),
},
{
ticket: 'seed_ticket_002',
toolId: 'tool_dl_002',
artifactId: 'art_101',
channel: 'cli',
clientVersion: '0.9.2',
requestIp: '10.24.88.12',
expiresAt: daysAgo(0, 13, 0),
consumedAt: daysAgo(0, 12, 10),
createdAt: daysAgo(0, 12, 0),
},
{
ticket: 'seed_ticket_003',
toolId: 'tool_dl_003',
artifactId: 'art_202',
channel: 'agent',
clientVersion: '2.1.0',
requestIp: '10.24.88.13',
expiresAt: daysAgo(1, 14, 0),
consumedAt: null,
createdAt: daysAgo(1, 13, 20),
},
{
ticket: 'seed_ticket_004',
toolId: 'tool_dl_001',
artifactId: 'art_002',
channel: 'desktop',
clientVersion: '1.1.0',
requestIp: '10.24.88.14',
expiresAt: daysAgo(3, 10, 0),
consumedAt: daysAgo(3, 9, 12),
createdAt: daysAgo(3, 9, 0),
},
{
ticket: 'seed_ticket_005',
toolId: 'tool_dl_003',
artifactId: 'art_202',
channel: 'agent',
clientVersion: '2.1.0',
requestIp: '10.24.88.15',
expiresAt: daysAgo(6, 17, 0),
consumedAt: null,
createdAt: daysAgo(6, 16, 30),
},
],
});
await prisma.adminAuditLog.createMany({
data: [
{
adminUserId: 'u_admin_001',
action: 'LOGIN',
resourceType: 'auth',
resourceId: 'u_admin_001',
requestMethod: 'POST',
requestPath: '/admin/auth/login',
requestBody: JSON.stringify({ username: 'admin' }),
ip: '10.24.77.10',
userAgent: USER_AGENTS[0],
createdAt: daysAgo(0, 9, 25),
},
{
adminUserId: 'u_admin_001',
action: 'CREATE_TOOL',
resourceType: 'tool',
resourceId: 'tool_draft_001',
requestMethod: 'POST',
requestPath: '/admin/tools',
requestBody: JSON.stringify({
name: 'Local Agent Kit',
accessMode: 'download',
}),
ip: '10.24.77.10',
userAgent: USER_AGENTS[0],
createdAt: daysAgo(0, 10, 5),
},
{
adminUserId: 'u_admin_002',
action: 'UPLOAD_ARTIFACT',
resourceType: 'artifact',
resourceId: 'art_202',
requestMethod: 'POST',
requestPath: '/admin/tools/tool_dl_003/artifacts',
requestBody: JSON.stringify({ version: '2.1.0' }),
ip: '10.24.77.21',
userAgent: USER_AGENTS[1],
createdAt: daysAgo(1, 14, 12),
},
{
adminUserId: 'u_admin_002',
action: 'SET_LATEST_ARTIFACT',
resourceType: 'tool',
resourceId: 'tool_dl_003',
requestMethod: 'PATCH',
requestPath: '/admin/tools/tool_dl_003/artifacts/art_202/latest',
requestBody: null,
ip: '10.24.77.21',
userAgent: USER_AGENTS[1],
createdAt: daysAgo(1, 14, 18),
},
{
adminUserId: 'u_admin_001',
action: 'UPDATE_TOOL_STATUS',
resourceType: 'tool',
resourceId: 'tool_dl_001',
requestMethod: 'PATCH',
requestPath: '/admin/tools/tool_dl_001/status',
requestBody: JSON.stringify({ status: 'published' }),
ip: '10.24.77.10',
userAgent: USER_AGENTS[0],
createdAt: daysAgo(2, 11, 40),
},
{
adminUserId: 'u_admin_002',
action: 'UPDATE_TOOL',
resourceType: 'tool',
resourceId: 'tool_web_004',
requestMethod: 'PUT',
requestPath: '/admin/tools/tool_web_004',
requestBody: JSON.stringify({ openInNewTab: false }),
ip: '10.24.77.21',
userAgent: USER_AGENTS[2],
createdAt: daysAgo(2, 17, 5),
},
{
adminUserId: 'u_admin_001',
action: 'CREATE_CATEGORY',
resourceType: 'category',
resourceId: 'cat_productivity',
requestMethod: 'POST',
requestPath: '/admin/categories',
requestBody: JSON.stringify({ name: 'Productivity' }),
ip: '10.24.77.10',
userAgent: USER_AGENTS[0],
createdAt: daysAgo(3, 9, 45),
},
{
adminUserId: 'u_admin_001',
action: 'CREATE_TAG',
resourceType: 'tag',
resourceId: 'tag_recommended',
requestMethod: 'POST',
requestPath: '/admin/tags',
requestBody: JSON.stringify({ name: 'Recommended' }),
ip: '10.24.77.10',
userAgent: USER_AGENTS[0],
createdAt: daysAgo(3, 10, 10),
},
{
adminUserId: 'u_admin_002',
action: 'UPDATE_ARTIFACT_STATUS',
resourceType: 'artifact',
resourceId: 'art_001',
requestMethod: 'PATCH',
requestPath: '/admin/tools/tool_dl_001/artifacts/art_001/status',
requestBody: JSON.stringify({ status: 'deprecated' }),
ip: '10.24.77.21',
userAgent: USER_AGENTS[3],
createdAt: daysAgo(4, 15, 30),
},
{
adminUserId: 'u_admin_002',
action: 'LOGIN',
resourceType: 'auth',
resourceId: 'u_admin_002',
requestMethod: 'POST',
requestPath: '/admin/auth/login',
requestBody: JSON.stringify({ username: 'ops-admin' }),
ip: '10.24.77.21',
userAgent: USER_AGENTS[1],
createdAt: daysAgo(5, 8, 55),
},
{
adminUserId: 'u_admin_001',
action: 'DELETE_ARTIFACT',
resourceType: 'artifact',
resourceId: 'art_201',
requestMethod: 'DELETE',
requestPath: '/admin/tools/tool_dl_003/artifacts/art_201',
requestBody: null,
ip: '10.24.77.10',
userAgent: USER_AGENTS[0],
createdAt: daysAgo(6, 16, 40),
},
{
adminUserId: null,
action: 'SYSTEM_BOOTSTRAP',
resourceType: 'system',
resourceId: null,
requestMethod: 'POST',
requestPath: '/system/bootstrap',
requestBody: JSON.stringify({ source: 'seed' }),
ip: '127.0.0.1',
userAgent: 'seed-script',
createdAt: daysAgo(6, 7, 0),
},
],
2026-03-27 10:18:26 +08:00
});
}
main()
.catch(async (error) => {
console.error(error);
process.exitCode = 1;
})
.finally(async () => {
await prisma.$disconnect();
});