992 lines
28 KiB
TypeScript
992 lines
28 KiB
TypeScript
import argon2 from 'argon2';
|
|
import {
|
|
PrismaClient,
|
|
AccessMode,
|
|
ToolStatus,
|
|
ArtifactStatus,
|
|
DownloadRecordStatus,
|
|
AdminUserStatus,
|
|
} from '@prisma/client';
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
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;
|
|
versionOverride?: 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);
|
|
}
|
|
|
|
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,
|
|
}));
|
|
});
|
|
}
|
|
|
|
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,
|
|
versionOverride: tool.versionOverride,
|
|
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() {
|
|
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 },
|
|
{ id: 'cat_design', name: 'Design', sortOrder: 40 },
|
|
{ id: 'cat_productivity', name: 'Productivity', sortOrder: 50 },
|
|
],
|
|
});
|
|
|
|
await prisma.tag.createMany({
|
|
data: [
|
|
{ id: 'tag_hot', name: 'Hot' },
|
|
{ id: 'tag_free', name: 'Free' },
|
|
{ id: 'tag_official', name: 'Official' },
|
|
{ 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' },
|
|
],
|
|
});
|
|
|
|
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),
|
|
},
|
|
],
|
|
});
|
|
|
|
const tools: ToolSeed[] = [
|
|
{
|
|
id: 'tool_web_001',
|
|
name: 'OpenAI Playground',
|
|
slug: 'openai-playground',
|
|
categoryId: 'cat_ai',
|
|
description:
|
|
'OpenAI web playground for prompt iteration, parameter tuning, and quick eval loops.',
|
|
rating: 4.9,
|
|
downloadCount: 0,
|
|
openCount: 642,
|
|
accessMode: AccessMode.web,
|
|
openUrl: 'https://platform.openai.com/playground',
|
|
versionOverride: '2026.04',
|
|
openInNewTab: true,
|
|
status: ToolStatus.published,
|
|
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,
|
|
},
|
|
{
|
|
id: 'feat_web_003',
|
|
featureText: 'Quick compare workflow',
|
|
sortOrder: 30,
|
|
},
|
|
],
|
|
tagIds: ['tag_hot', 'tag_official', 'tag_recommended'],
|
|
},
|
|
{
|
|
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',
|
|
versionOverride: '2026.03',
|
|
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',
|
|
versionOverride: 'atlas-3.2',
|
|
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',
|
|
versionOverride: 'workflow-1.8',
|
|
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',
|
|
name: 'ToolsShow Desktop',
|
|
slug: 'toolsshow-desktop',
|
|
categoryId: 'cat_dev',
|
|
description:
|
|
'Desktop bundle for local workflows, offline browsing, and curated plugin execution.',
|
|
rating: 4.8,
|
|
downloadCount: 182,
|
|
openCount: 0,
|
|
accessMode: AccessMode.download,
|
|
versionOverride: 'stable-1.1',
|
|
status: ToolStatus.published,
|
|
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,
|
|
},
|
|
],
|
|
tagIds: ['tag_hot', 'tag_free', 'tag_recommended'],
|
|
artifacts: [
|
|
{
|
|
id: 'art_001',
|
|
version: '1.0.0',
|
|
fileName: 'toolsshow-desktop-1.0.0.zip',
|
|
fileSizeBytes: 12345678,
|
|
sha256: 'sha256-toolsshow-100',
|
|
mimeType: 'application/zip',
|
|
gitlabProjectId: 1001,
|
|
gitlabPackageName: 'toolsshow/toolsshow-desktop',
|
|
gitlabPackageVersion: '1.0.0',
|
|
gitlabFilePath: 'storage/toolsshow-desktop-1.0.0.zip',
|
|
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',
|
|
status: ArtifactStatus.active,
|
|
releaseNotes: 'Adds plugin auto-update and workspace pinning.',
|
|
uploadedBy: 'u_admin_002',
|
|
createdAt: daysAgo(8, 16, 45),
|
|
},
|
|
],
|
|
latestArtifactId: 'art_002',
|
|
},
|
|
{
|
|
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,
|
|
versionOverride: 'stable-2.1',
|
|
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_none_001',
|
|
name: 'Prompt Catalog Preview',
|
|
slug: 'prompt-catalog-preview',
|
|
categoryId: 'cat_ai',
|
|
description:
|
|
'Preview-only catalog for upcoming internal prompt packs, curation notes, and launch plans.',
|
|
rating: 4.1,
|
|
downloadCount: 0,
|
|
openCount: 0,
|
|
accessMode: AccessMode.none,
|
|
versionOverride: 'preview-2026.04',
|
|
status: ToolStatus.published,
|
|
createdAt: daysAgo(7, 15, 20),
|
|
updatedAt: dateOnly(daysAgo(0)),
|
|
features: [
|
|
{
|
|
id: 'feat_none_001',
|
|
featureText: 'Upcoming prompt pack roadmap',
|
|
sortOrder: 10,
|
|
},
|
|
{
|
|
id: 'feat_none_002',
|
|
featureText: 'Preview-only release notes',
|
|
sortOrder: 20,
|
|
},
|
|
{
|
|
id: 'feat_none_003',
|
|
featureText: 'Owner and rollout visibility',
|
|
sortOrder: 30,
|
|
},
|
|
],
|
|
tagIds: ['tag_new', 'tag_team'],
|
|
},
|
|
{
|
|
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'],
|
|
},
|
|
];
|
|
|
|
for (const tool of tools) {
|
|
await createToolWithRelations(tool);
|
|
}
|
|
|
|
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: '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 },
|
|
],
|
|
});
|
|
|
|
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),
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
main()
|
|
.catch(async (error) => {
|
|
console.error(error);
|
|
process.exitCode = 1;
|
|
})
|
|
.finally(async () => {
|
|
await prisma.$disconnect();
|
|
});
|