# 项目发现工作流 (Project Discovery Workflow) 本文档详细说明了 AI 项目自动发现和收录的完整工作流程。 ## 📋 工作流概览 ``` ┌─────────────────────────────────────────────────────────────────┐ │ 项目发现完整流程 │ └─────────────────────────────────────────────────────────────────┘ 1. n8n 自动化平台 │ ├─ 定期抓取 GitHub/Twitter/HackerNews 等平台 ├─ 筛选符合条件的项目链接 │ ▼ 2. 调用去重检查 API (推荐) POST /api/discovery/check-duplicates │ ├─ 检查 URL 是否已存在任务 ├─ 检查 URL 对应项目是否已收录 ├─ 过滤出需要创建的 URL │ ▼ 3. 调用创建任务 API POST /api/discovery/tasks │ ├─ 存入 ProjectDiscoveryTask 表 ├─ 状态: PENDING │ ▼ 4. 手动触发本地命令 (定期执行) /discover-projects │ ├─ 通过 curl 获取待处理任务 ├─ 调用 Content Explorer Agent │ ├─ 使用 agent-browser 探索项目 │ ├─ 提取项目信息 (README, 代码结构等) │ ├─ 生成结构化 JSON 数据 │ └─ 应用内容质量标准 │ ├─ 调用 API Submitter Agent │ ├─ 批量标记任务为 IN_PROGRESS │ ├─ 提交探索数据到完成 API │ └─ 自动重试失败的提交 │ ▼ 5. 完成任务并入库 POST /api/discovery/tasks/{id}/complete │ ├─ 验证数据格式 (Zod Schema) ├─ 多级去重检测 (GitHub/Website URL) ├─ 创建或更新 Project ├─ 创建 Tag 和关联关系 ├─ 创建 ExternalLink │ ├─ 更新任务状态: COMPLETED/FAILED │ ▼ 6. 数据已入库,可在前台展示 ``` --- ## 🔄 详细步骤说明 ### 步骤 1: n8n 自动收集项目链接 **平台**: n8n 自动化平台 (独立部署) **工作内容**: - 定期抓取 GitHub Trending、Twitter、HackerNews 等平台 - 根据关键词筛选 AI 相关项目 - 提取项目的基本信息 (名称、链接、简介等) **输出数据格式**: ```json { "sourceUrl": "https://github.com/langchain-ai/langchain", "sourceType": "github_trending" // 或 "twitter", "hackernews" 等 } ``` --- ### 步骤 2: 调用创建任务 API **API 端点**: `POST /api/discovery/tasks` **调用示例**: ```bash curl -X POST https://your-domain.com/api/discovery/tasks \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -d '{ "apiKey": "YOUR_API_KEY", "tasks": [ { "sourceUrl": "https://github.com/langchain-ai/langchain", "sourceType": "github_trending" }, { "sourceUrl": "https://github.com/openai/openai-quickstart-python", "sourceType": "github_trending" } ] }' ``` **数据库变更**: - 在 `ProjectDiscoveryTask` 表中插入新记录 - `status` = `PENDING` - `sourceUrl` 和 `sourceType` 来自 n8n - `createdAt` = 当前时间 --- ### 步骤 2.5: 调用去重检查 API(推荐) **API 端点**: `POST /api/discovery/check-duplicates` **调用示例**: ```bash curl -X POST https://your-domain.com/api/discovery/check-duplicates \ -H "Content-Type: application/json" \ -d '{ "apiKey": "YOUR_API_KEY", "urls": [ "https://github.com/langchain-ai/langchain", "https://github.com/openai/openai-quickstart-python" ] }' ``` **返回结果**: ```json { "success": true, "results": [ { "url": "https://github.com/langchain-ai/langchain", "shouldCreate": false, "reason": "Task already exists with status PENDING", "existingTask": { "id": "cmxxxxx", "status": "PENDING", "sourceUrl": "https://github.com/langchain-ai/langchain", "createdAt": "2025-01-18T10:00:00Z", "projectId": null } }, { "url": "https://github.com/openai/openai-quickstart-python", "shouldCreate": true, "reason": "No existing task or project found" } ], "stats": { "total": 2, "shouldCreate": 1, "duplicate": 1 } } ``` **去重逻辑**(按优先级): 1. **优先级 1**: 检查是否有 PENDING/IN_PROGRESS 的相同 URL 任务 - 如果存在 → `shouldCreate: false` - 原因:任务已在处理中,避免重复探索 2. **优先级 2**: 检查是否有 COMPLETED/FAILED 的相同 URL 任务 - 如果存在 → `shouldCreate: false` - 原因:任务已探索过,无需重复 3. **优先级 3**: 检查 URL 对应的项目是否已存在(通过 ExternalLink) - 如果存在 → `shouldCreate: false` - 原因:项目已通过其他来源收录 4. **默认**: 允许创建新任务 - `shouldCreate: true` **n8n 集成建议**: ```javascript // n8n Workflow 示例 const checkResponse = await fetch('https://your-domain.com/api/discovery/check-duplicates', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ apiKey: 'YOUR_API_KEY', urls: collectedUrls // 从上一步收集的 URL 列表 }) }) const { results, stats } = await checkResponse.json() // 过滤出应该创建任务的 URL const urlsToCreate = results .filter(r => r.shouldCreate) .map(r => r.url) // 只为不重复的 URL 创建任务 if (urlsToCreate.length > 0) { await fetch('https://your-domain.com/api/discovery/tasks', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ apiKey: 'YOUR_API_KEY', tasks: urlsToCreate.map(url => ({ sourceUrl: url, sourceType: 'github_trending' })) }) }) } console.log(`创建 ${urlsToCreate.length} 个新任务,跳过 ${stats.duplicate} 个重复任务`) ``` --- ### 步骤 3: 手动触发本地命令 **执行环境**: 本地开发环境 (Local Development) **执行命令**: ```bash # 处理默认 10 个任务 (每批 3 个) /discover-projects # 处理指定数量的任务 /discover-projects 20 # 自定义批次大小 /discover-projects 9 --batch=2 # 处理所有待处理任务 /discover-projects all --batch=5 ``` **命令执行流程**: 1. 通过 curl 调用 `GET /api/discovery/tasks?status=PENDING&limit=N` 2. 获取待处理的任务列表 3. 分批处理 (默认每批 3 个任务) 4. 为每个任务启动 **Content Explorer Agent** --- ### 步骤 3.1: Content Explorer Agent (项目探索) **Agent 定义**: `.claude/agents/content-explorer-agent.md` **核心能力**: - 使用 `agent-browser` 子任务并行探索 GitHub 项目 - 访问项目主页、README、代码结构 - 提取项目元数据 (名称、描述、标签、链接等) - 生成符合 `ProjectInputSchema` 的 JSON 数据 **内容质量标准** (参考: `.claude/schemas/project-content-template.md`): - ✅ **描述**: 客观说明功能、突出价值、避免营销术语、10-500字 - ✅ **内容**: 从 README 提取并重新组织、符合中文表达习惯 - ✅ **链接**: 必须包含 GITHUB 链接、所有链接可访问 - ✅ **标签**: 1-10 个标签、按技术/应用/状态分类 - ✅ **动态数据**: Star/Fork 等动态数据不写入内容,使用 GitHub Badge **输出数据格式**: ```json { "name": "LangChain", "nameEn": "LangChain", "description": "开发由 LLM 驱动的应用程序的框架,提供文档加载、文本分割、向量存储等核心组件", "descriptionEn": "Framework for developing applications powered by language models", "content": "## 核心功能\n\n- 文档加载: 支持 PDF、TXT、网页等多种格式\n- 文本分割: 智能分割长文本\n...", "tags": [ { "name": "LLM", "nameEn": "Large Language Model" }, { "name": "框架", "nameEn": "Framework" } ], "links": [ { "type": "GITHUB", "url": "https://github.com/langchain-ai/langchain", "title": "GitHub 仓库" }, { "type": "WEBSITE", "url": "https://python.langchain.com", "title": "官方文档" } ], "status": "ACTIVE" } ``` --- ### 步骤 3.2: API Submitter Agent (数据提交) **Agent 定义**: `.claude/agents/api-submitter-agent.md` **核心能力**: - 批量标记任务为 `IN_PROGRESS` - 调用 `POST /api/discovery/tasks/{id}/complete` 提交数据 - 自动重试失败的提交 (指数退避,最多 3 次) - 处理部分成功/失败情况 **提交流程**: ``` 1. PATCH /api/discovery/tasks/{id} → status=IN_PROGRESS ↓ 2. POST /api/discovery/tasks/{id}/complete → 提交探索数据 ↓ 3. 检查响应 ├─ 成功 → 标记任务完成 ├─ 失败 → 重试 (最多 3 次) └─ 最终失败 → 记录错误信息 ``` --- ### 步骤 4: 完成任务并入库 **API 端点**: `POST /api/discovery/tasks/{id}/complete` **处理逻辑** (参考: `src/app/api/discovery/tasks/[id]/complete/route.ts`): 1. **验证数据格式**: 使用 `ProjectInputSchema` 验证 2. **多级去重检测**: - 优先级 1: GitHub URL 精确匹配 - 优先级 2: Website URL 精确匹配 - 优先级 3: slug 匹配 3. **创建或更新项目**: - 如果存在重复项目 → 更新所有字段、标签、链接 - 如果不存在 → 创建新项目 4. **更新任务状态**: - 成功 → `COMPLETED` - 失败 → `FAILED` (记录错误信息) **数据库变更**: - `Project` 表: 创建或更新记录 - `Tag` 表: Upsert 标签 - `ProjectTag` 表: 创建关联关系 - `ExternalLink` 表: 创建或更新链接 - `ProjectDiscoveryTask` 表: 更新 `status`、`projectId`、`completedAt` --- ## 🗂️ 数据模型关系 ``` ProjectDiscoveryTask (任务表) ├─ id: String (主键) ├─ status: TaskStatus (PENDING/IN_PROGRESS/COMPLETED/FAILED) ├─ sourceUrl: String (n8n 提供的原始 URL) ├─ sourceType: String (github_trending/twitter/hackernews) ├─ explorationData: Json (Agent 探索结果) ├─ explorationSummary: String (探索摘要) ├─ projectId: String (关联到 Project.id) ├─ errorMessage: String (失败原因) └─ createdAt/startedAt/completedAt: DateTime Project (项目表) ← 通过 projectId 关联 ├─ id, name, nameEn, slug ├─ description, descriptionEn ├─ content, contentEn ├─ status (ACTIVE/ARCHIVED) └─ 关联: tags, links, discoveryTasks Tag (标签表) └─ 通过 ProjectTag 多对多关联 ExternalLink (外部链接表) └─ 通过 projectId 一对多关联 ``` --- ## 🔧 环境配置 ### 环境变量 ```env # .env.local (本地开发) WEBHOOK_API_KEY=your-production-api-key-here # 用于调用完成 API # 生产环境 (Vercel Dashboard 配置) DATABASE_URL=postgres://... WEBHOOK_API_KEY=your-production-api-key-here ``` ### 依赖服务 1. **n8n 平台**: - 独立部署 (自托管或云服务) - 配置定时工作流 (Workflow) - 存储 `WEBHOOK_API_KEY` 用于 API 调用 2. **本地开发环境**: - Node.js 18+ - pnpm 包管理器 - Claude Code CLI (支持斜杠命令) 3. **生产环境**: - Vercel (Next.js 部署) - Neon PostgreSQL (数据库) --- ## 📊 执行监控 ### 查看待处理任务 ```bash # 查询待处理任务数量 curl https://your-domain.com/api/discovery/tasks?status=PENDING&limit=100 # 查询进行中的任务 curl https://your-domain.com/api/discovery/tasks?status=IN_PROGRESS # 查询失败的任务 (需要重试) curl https://your-domain.com/api/discovery/tasks?status=FAILED ``` ### 重试失败任务 ```bash # 手动重试失败的任务 /discover-projects 10 --status=FAILED ``` --- ## 🎯 质量保障 ### 内容质量标准 (详细参考: `.claude/schemas/project-content-template.md`) 1. **描述要求**: - 清晰说明项目的核心功能 - 突出项目的独特价值 - 避免使用营销术语 ("最好"、"第一"、"革命性" 等) - 字数控制在 10-500 字 2. **内容要求**: - 从项目 README 提取并重新组织 - 避免机械翻译,符合中文表达习惯 - 支持 Markdown 格式 - 动态数据 (Star/Fork) 不写入内容 3. **链接要求**: - 必须包含 GITHUB 链接 - 所有链接必须可访问 - 链接类型必须正确 (WEBSITE/GITHUB/HUGGINGFACE/PAPER) 4. **标签要求**: - 1-10 个标签 - 按技术栈/应用领域/开发状态分类 - 中英文对应 ### 数据验证 所有提交的数据必须通过 `ProjectInputSchema` 验证 (详见 `src/lib/validations.ts`): ```typescript ProjectInputSchema { name: string (1-200字符, 必填) description: string (10-500字符, 必填) tags: Tag[] (1-10个, 必填) links: ExternalLink[] (1-10个, 必填) nameEn?: string (1-200字符) descriptionEn?: string content?: string (Markdown, 最多10000字符) contentEn?: string status?: "ACTIVE" | "ARCHIVED" source?: string } ``` --- ## 🚀 快速开始 ### 第一次使用 1. **配置 n8n 工作流**: - 创建新的 n8n Workflow - 配置定时触发器 (如每天凌晨 2 点) - 添加 HTTP Request 节点调用 `POST /api/discovery/tasks` 2. **本地执行命令**: ```bash # 启动开发服务器 (如果未运行) pnpm dev # 执行项目发现命令 /discover-projects ``` 3. **查看结果**: - 访问 https://your-domain.com 查看新收录的项目 - 检查数据库确认数据正确性 ### 日常维护 1. **定期执行命令** (建议每天 1-2 次): ```bash /discover-projects 20 ``` 2. **监控失败任务**: - 检查 `status=FAILED` 的任务 - 分析错误原因 (网络问题、数据格式等) - 必要时手动重试 3. **优化内容质量**: - 随机抽查已收录项目的描述和内容 - 调整 Agent 的提示词以提升质量 --- ## 🔍 故障排查 ### 常见问题 1. **任务长时间处于 IN_PROGRESS 状态**: - 可能原因: Agent 探索超时、网络问题 - 解决方案: 手动更新任务状态为 PENDING 后重试 2. **大量任务失败**: - 检查 `errorMessage` 字段 - 常见原因: 数据格式不正确、URL 无法访问、API Key 错误 3. **重复项目被创建**: - 检查去重逻辑是否正常工作 - 确认 `ExternalLink` 表的索引 `idx_link_type_url` 存在 4. **n8n 无法调用 API**: - 检查 `WEBHOOK_API_KEY` 是否正确配置 - 确认 API 端点可访问 - 查看 n8n 执行日志 --- ## 📚 相关文档 - **API 参考**: `docs/api-reference.md` - **数据模型**: `prisma/schema.prisma` - **验证规则**: `src/lib/validations.ts` - **Agent 定义**: `.claude/agents/content-explorer-agent.md` - **Agent 定义**: `.claude/agents/api-submitter-agent.md` - **内容质量标准**: `.claude/schemas/project-content-template.md` - **项目主文档**: `CLAUDE.md` --- ## 📝 更新日志 - **2025-01-18**: 创建文档,记录完整的项目发现工作流