feat: 实现 Agent Park AI 项目导航网站核心功能
完成 Next.js 14+ 全栈应用的 MVP 实现,包含以下功能: ## 项目设置 - 初始化 Next.js 14+ 项目,配置 TypeScript 严格模式 - 配置 Tailwind CSS、ESLint、Prettier 代码质量工具 - 集成 shadcn/ui 组件库和 next-intl 国际化方案 ## 数据层 - 配置 PostgreSQL + Prisma ORM - 定义 Project、Tag、ExternalLink 数据模型 - 实现种子数据脚本(5个AI项目) ## 用户故事 1:浏览和搜索 AI 项目 - 实现首页,展示热门标签云和精选项目 - 实现项目列表页,支持搜索和标签筛选 - 创建 TagCloud、ProjectCard、ProjectList、SearchBar 组件 - 实现 ISR 缓存策略优化性能 ## 用户故事 2:查看项目详细信息 - 实现项目详情页,显示完整信息 - 创建 ExternalLinkCard 组件展示外部链接 - 实现安全的 target="_blank" 外链跳转 ## 用户故事 4:数据更新和管理 - 实现 webhook API 端点接收 n8n 数据推送 - 实现 API Key 身份验证 - 支持部分成功模式的批量数据处理 - 完善的错误处理和日志记录 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
previewFeatures = ["postgresqlExtensions"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Enums
|
||||
// ================================
|
||||
|
||||
enum ProjectStatus {
|
||||
ACTIVE
|
||||
ARCHIVED
|
||||
}
|
||||
|
||||
enum LinkType {
|
||||
WEBSITE
|
||||
GITHUB
|
||||
HUGGINGFACE
|
||||
PAPER
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Models
|
||||
// ================================
|
||||
|
||||
model Project {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
nameEn String?
|
||||
slug String @unique
|
||||
description String
|
||||
descriptionEn String?
|
||||
content String? @db.Text
|
||||
contentEn String? @db.Text
|
||||
status ProjectStatus @default(ACTIVE)
|
||||
source String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relations
|
||||
tags Tag[]
|
||||
links ExternalLink[]
|
||||
|
||||
// Indexes
|
||||
@@index([status, createdAt], map: "idx_project_status_createdAt")
|
||||
@@index([slug], map: "idx_project_slug")
|
||||
@@map("projects")
|
||||
}
|
||||
|
||||
model Tag {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
nameEn String?
|
||||
slug String @unique
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
// Relations
|
||||
projects Project[]
|
||||
|
||||
// Indexes
|
||||
@@index([slug], map: "idx_tag_slug")
|
||||
@@map("tags")
|
||||
}
|
||||
|
||||
model ExternalLink {
|
||||
id String @id @default(cuid())
|
||||
type LinkType
|
||||
url String
|
||||
title String?
|
||||
projectId String
|
||||
|
||||
// Relations
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
|
||||
// Indexes
|
||||
@@index([projectId], map: "idx_link_projectId")
|
||||
@@index([type], map: "idx_link_type")
|
||||
@@map("external_links")
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
import { PrismaClient, ProjectStatus, LinkType } from '@prisma/client'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
async function main() {
|
||||
console.log('Starting seed...')
|
||||
|
||||
// 创建标签
|
||||
const tags = await Promise.all([
|
||||
prisma.tag.upsert({
|
||||
where: { slug: 'code-assistant' },
|
||||
update: {},
|
||||
create: {
|
||||
name: '代码助手',
|
||||
nameEn: 'Code Assistant',
|
||||
slug: 'code-assistant'
|
||||
}
|
||||
}),
|
||||
prisma.tag.upsert({
|
||||
where: { slug: 'image-generation' },
|
||||
update: {},
|
||||
create: {
|
||||
name: '图像生成',
|
||||
nameEn: 'Image Generation',
|
||||
slug: 'image-generation'
|
||||
}
|
||||
}),
|
||||
prisma.tag.upsert({
|
||||
where: { slug: 'data-analysis' },
|
||||
update: {},
|
||||
create: {
|
||||
name: '数据分析',
|
||||
nameEn: 'Data Analysis',
|
||||
slug: 'data-analysis'
|
||||
}
|
||||
}),
|
||||
prisma.tag.upsert({
|
||||
where: { slug: 'chatbot' },
|
||||
update: {},
|
||||
create: {
|
||||
name: '对话AI',
|
||||
nameEn: 'Chatbot',
|
||||
slug: 'chatbot'
|
||||
}
|
||||
}),
|
||||
prisma.tag.upsert({
|
||||
where: { slug: 'automation' },
|
||||
update: {},
|
||||
create: {
|
||||
name: '自动化',
|
||||
nameEn: 'Automation',
|
||||
slug: 'automation'
|
||||
}
|
||||
})
|
||||
])
|
||||
|
||||
console.log(`Created ${tags.length} tags`)
|
||||
|
||||
// 创建项目
|
||||
const projects = [
|
||||
{
|
||||
name: 'Claude',
|
||||
nameEn: 'Claude',
|
||||
slug: 'claude',
|
||||
description: 'Anthropic 开发的 AI 助手,擅长分析、写作和编程任务。',
|
||||
descriptionEn: 'AI assistant by Anthropic, excels at analysis, writing, and coding.',
|
||||
content: 'Claude 是由 Anthropic 开发的下一代 AI 助手。它基于 Constitutional AI 方法训练,强调安全性、诚实性和有用性。',
|
||||
contentEn: 'Claude is a next-generation AI assistant developed by Anthropic. Trained using Constitutional AI methods.',
|
||||
tagSlugs: ['code-assistant', 'chatbot'],
|
||||
links: [
|
||||
{ type: LinkType.WEBSITE, url: 'https://www.anthropic.com/claude', title: 'Official Website' },
|
||||
{ type: LinkType.GITHUB, url: 'https://github.com/anthropics', title: 'GitHub' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'ChatGPT',
|
||||
nameEn: 'ChatGPT',
|
||||
slug: 'chatgpt',
|
||||
description: 'OpenAI 开发的大型语言模型,支持对话、写作、编程等多种任务。',
|
||||
descriptionEn: 'Large language model by OpenAI, supports conversation, writing, coding, etc.',
|
||||
tagSlugs: ['chatbot', 'code-assistant'],
|
||||
links: [
|
||||
{ type: LinkType.WEBSITE, url: 'https://chat.openai.com', title: 'Official Website' },
|
||||
{ type: LinkType.GITHUB, url: 'https://github.com/openai', title: 'GitHub' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Midjourney',
|
||||
nameEn: 'Midjourney',
|
||||
slug: 'midjourney',
|
||||
description: '强大的 AI 图像生成工具,通过文字描述创建精美图像。',
|
||||
descriptionEn: 'Powerful AI image generation tool that creates stunning images from text descriptions.',
|
||||
tagSlugs: ['image-generation'],
|
||||
links: [
|
||||
{ type: LinkType.WEBSITE, url: 'https://www.midjourney.com', title: 'Official Website' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Stable Diffusion',
|
||||
nameEn: 'Stable Diffusion',
|
||||
slug: 'stable-diffusion',
|
||||
description: '开源的图像生成模型,支持本地部署和自定义训练。',
|
||||
descriptionEn: 'Open-source image generation model, supports local deployment and custom training.',
|
||||
tagSlugs: ['image-generation'],
|
||||
links: [
|
||||
{ type: LinkType.WEBSITE, url: 'https://stability.ai', title: 'Official Website' },
|
||||
{ type: LinkType.GITHUB, url: 'https://github.com/Stability-AI', title: 'GitHub' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'n8n',
|
||||
nameEn: 'n8n',
|
||||
slug: 'n8n',
|
||||
description: '开源的工作流自动化工具,通过可视化界面连接各种服务和 API。',
|
||||
descriptionEn: 'Open-source workflow automation tool that connects various services and APIs via visual interface.',
|
||||
tagSlugs: ['automation'],
|
||||
links: [
|
||||
{ type: LinkType.WEBSITE, url: 'https://n8n.io', title: 'Official Website' },
|
||||
{ type: LinkType.GITHUB, url: 'https://github.com/n8n-io/n8n', title: 'GitHub' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
for (const projectData of projects) {
|
||||
const { tagSlugs, links, ...rest } = projectData
|
||||
const projectTags = tags.filter(t => tagSlugs.includes(t.slug))
|
||||
|
||||
await prisma.project.upsert({
|
||||
where: { slug: rest.slug },
|
||||
update: {},
|
||||
create: {
|
||||
...rest,
|
||||
status: ProjectStatus.ACTIVE,
|
||||
source: 'manual',
|
||||
tags: {
|
||||
connect: projectTags.map(t => ({ id: t.id }))
|
||||
},
|
||||
links: {
|
||||
create: links
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
console.log(`Created ${projects.length} projects`)
|
||||
console.log('Seed completed successfully!')
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error('Error seeding database:', e)
|
||||
process.exit(1)
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect()
|
||||
})
|
||||
Reference in New Issue
Block a user