diff --git a/.claude/AGENTS.md b/.claude/AGENTS.md new file mode 100644 index 0000000..3856f02 --- /dev/null +++ b/.claude/AGENTS.md @@ -0,0 +1,67 @@ +# .claude/ - Custom Claude Configuration + + + +## OVERVIEW + +Custom Claude Code agents, commands, and settings for the agent_park project. + +## STRUCTURE + +``` +.claude/ +├── settings.json # Claude Code project settings +├── agents/ # Custom agent definitions +│ ├── content-explorer-agent.md +│ └── api-submitter-agent.md +└── commands/ # Custom slash commands + └── discover-projects.md +``` + +## CUSTOM AGENTS + +### content-explorer-agent +- **Purpose**: Explore GitHub projects and generate structured data +- **Capabilities**: Browser automation, content extraction, JSON generation +- **Output**: ProjectInputSchema-compliant JSON + +### api-submitter-agent +- **Purpose**: Submit exploration results to production API +- **Capabilities**: Batch task updates, API submission, retry logic +- **Requires**: `WEBHOOK_API_KEY` environment variable + +## CUSTOM COMMANDS + +### /discover-projects +Automated project discovery workflow: +```bash +/discover-projects [count] [--batch=N] +``` +- Default: 10 tasks, batch size 3 +- Coordinates content-explorer + api-submitter agents + +## FOR AI AGENTS + +### When Adding Agents/Commands + +1. Create `.md` file with agent/command definition +2. Follow existing templates (frontmatter + instructions) +3. Test with `/command-name` before committing + +### Agent Template Structure + +```markdown +--- +name: agent-name +description: What this agent does +tools: [Read, Grep, Glob, Bash] # Allowed tools +--- + +# Role +[Agent role description] + +# Instructions +[Detailed instructions] +``` + + diff --git a/.omc/project-memory.json b/.omc/project-memory.json new file mode 100644 index 0000000..92bd975 --- /dev/null +++ b/.omc/project-memory.json @@ -0,0 +1,320 @@ +{ + "version": "1.0.0", + "lastScanned": 1771588891228, + "projectRoot": "/Users/caihaohan/Code/agent_park", + "techStack": { + "languages": [ + { + "name": "JavaScript/TypeScript", + "version": null, + "confidence": "high", + "markers": [ + "package.json" + ] + }, + { + "name": "TypeScript", + "version": null, + "confidence": "high", + "markers": [ + "tsconfig.json" + ] + } + ], + "frameworks": [ + { + "name": "next", + "version": "15.1.11", + "category": "fullstack" + }, + { + "name": "react", + "version": "19.0.0", + "category": "frontend" + }, + { + "name": "react-dom", + "version": "19.0.0", + "category": "frontend" + }, + { + "name": "@playwright/test", + "version": "1.49.1", + "category": "testing" + }, + { + "name": "vitest", + "version": "2.1.8", + "category": "testing" + } + ], + "packageManager": "pnpm", + "runtime": null + }, + "build": { + "buildCommand": "pnpm build", + "testCommand": "pnpm test", + "lintCommand": "pnpm lint", + "devCommand": "pnpm dev", + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint", + "test": "vitest", + "test:e2e": "playwright test" + } + }, + "conventions": { + "namingStyle": null, + "importStyle": null, + "testPattern": null, + "fileOrganization": "type-based" + }, + "structure": { + "isMonorepo": false, + "workspaces": [], + "mainDirectories": [ + "docs", + "scripts", + "src", + "tests" + ], + "gitBranches": { + "defaultBranch": "main", + "branchingStrategy": null + } + }, + "customNotes": [], + "directoryMap": { + "design": { + "path": "design", + "purpose": null, + "fileCount": 3, + "lastAccessed": 1771588891214, + "keyFiles": [ + "detail.html", + "homepage.html", + "projectlist.html" + ] + }, + "docs": { + "path": "docs", + "purpose": "Documentation", + "fileCount": 7, + "lastAccessed": 1771588891218, + "keyFiles": [ + "analyst.md", + "api-reference.md", + "api-testing-guide.md", + "discovery-workflow.md", + "e2e-testing-guide.md" + ] + }, + "n8n-workflows": { + "path": "n8n-workflows", + "purpose": null, + "fileCount": 2, + "lastAccessed": 1771588891218, + "keyFiles": [ + "README.md", + "keyword-cloud-workflow.json" + ] + }, + "prisma": { + "path": "prisma", + "purpose": null, + "fileCount": 2, + "lastAccessed": 1771588891219, + "keyFiles": [ + "schema.prisma", + "seed.ts" + ] + }, + "scripts": { + "path": "scripts", + "purpose": "Build/utility scripts", + "fileCount": 4, + "lastAccessed": 1771588891219, + "keyFiles": [ + "list-tags.js", + "seed-historical-events.ts", + "seed-keyword-cloud.ts", + "test-keyword-api.ts" + ] + }, + "src": { + "path": "src", + "purpose": "Source code", + "fileCount": 1, + "lastAccessed": 1771588891219, + "keyFiles": [ + "middleware.ts" + ] + }, + "tests": { + "path": "tests", + "purpose": "Test files", + "fileCount": 0, + "lastAccessed": 1771588891219, + "keyFiles": [] + }, + "prisma/migrations": { + "path": "prisma/migrations", + "purpose": "Database migrations", + "fileCount": 1, + "lastAccessed": 1771588891220, + "keyFiles": [ + "migration_lock.toml" + ] + }, + "src/app": { + "path": "src/app", + "purpose": "Application code", + "fileCount": 3, + "lastAccessed": 1771588891220, + "keyFiles": [ + "AGENTS.md", + "globals.css", + "layout.tsx" + ] + }, + "src/components": { + "path": "src/components", + "purpose": "UI components", + "fileCount": 1, + "lastAccessed": 1771588891220, + "keyFiles": [ + "AGENTS.md" + ] + }, + "src/lib": { + "path": "src/lib", + "purpose": "Library code", + "fileCount": 6, + "lastAccessed": 1771588891220, + "keyFiles": [ + "AGENTS.md", + "prisma.ts", + "slug.ts" + ] + } + }, + "hotPaths": [ + { + "path": "AGENTS.md", + "accessCount": 6, + "lastAccessed": 1771593272139, + "type": "file" + }, + { + "path": ".opencode/mcp.json", + "accessCount": 4, + "lastAccessed": 1771592799554, + "type": "file" + }, + { + "path": "src/app/AGENTS.md", + "accessCount": 3, + "lastAccessed": 1771593311370, + "type": "file" + }, + { + "path": "src/hooks/AGENTS.md", + "accessCount": 3, + "lastAccessed": 1771593529726, + "type": "file" + }, + { + "path": "src/lib/AGENTS.md", + "accessCount": 3, + "lastAccessed": 1771593529730, + "type": "file" + }, + { + "path": "src/components/AGENTS.md", + "accessCount": 2, + "lastAccessed": 1771593512972, + "type": "file" + }, + { + "path": "prisma/schema.prisma", + "accessCount": 2, + "lastAccessed": 1771594876904, + "type": "file" + }, + { + "path": ".env", + "accessCount": 1, + "lastAccessed": 1771589498743, + "type": "file" + }, + { + "path": "package.json", + "accessCount": 1, + "lastAccessed": 1771593111981, + "type": "file" + }, + { + "path": "CLAUDE.md", + "accessCount": 1, + "lastAccessed": 1771593111989, + "type": "file" + }, + { + "path": "prisma/seed.ts", + "accessCount": 1, + "lastAccessed": 1771593360708, + "type": "file" + }, + { + "path": "prisma/AGENTS.md", + "accessCount": 1, + "lastAccessed": 1771593361809, + "type": "file" + }, + { + "path": "docs/analyst.md", + "accessCount": 1, + "lastAccessed": 1771594824291, + "type": "file" + }, + { + "path": "docs/plans/2025-01-25-ai-timeline-feature-design.md", + "accessCount": 1, + "lastAccessed": 1771594834076, + "type": "file" + }, + { + "path": "docs/plans/2026-01-25-keyword-cloud-system-design.md", + "accessCount": 1, + "lastAccessed": 1771594834081, + "type": "file" + }, + { + "path": "docs/plans/2025-01-25-ai-timeline-implementation.md", + "accessCount": 1, + "lastAccessed": 1771594834472, + "type": "file" + }, + { + "path": "docs/plans/2026-01-25-keyword-cloud-implementation.md", + "accessCount": 1, + "lastAccessed": 1771594834666, + "type": "file" + }, + { + "path": "src/app/[locale]/timeline/page.tsx", + "accessCount": 1, + "lastAccessed": 1771594876522, + "type": "file" + }, + { + "path": "src/app/[locale]/keyword-cloud/components/KeywordCloud.tsx", + "accessCount": 1, + "lastAccessed": 1771594892847, + "type": "file" + } + ], + "userDirectives": [] +} \ No newline at end of file diff --git a/.omc/state/agent-replay-06edd4b9-cb01-44f4-a4af-c05ffc72c09e.jsonl b/.omc/state/agent-replay-06edd4b9-cb01-44f4-a4af-c05ffc72c09e.jsonl new file mode 100644 index 0000000..7f7a0f3 --- /dev/null +++ b/.omc/state/agent-replay-06edd4b9-cb01-44f4-a4af-c05ffc72c09e.jsonl @@ -0,0 +1 @@ +{"t":0,"agent":"a37a7c5","agent_type":"unknown","event":"agent_stop","success":true} diff --git a/.omc/state/agent-replay-142c3208-f900-46e0-bf24-573ef3f800d4.jsonl b/.omc/state/agent-replay-142c3208-f900-46e0-bf24-573ef3f800d4.jsonl new file mode 100644 index 0000000..3a3e2e1 --- /dev/null +++ b/.omc/state/agent-replay-142c3208-f900-46e0-bf24-573ef3f800d4.jsonl @@ -0,0 +1 @@ +{"t":0,"agent":"a8591e0","agent_type":"unknown","event":"agent_stop","success":true} diff --git a/.omc/state/agent-replay-572cfe5e-cb62-41f5-94c6-37d47939ae85.jsonl b/.omc/state/agent-replay-572cfe5e-cb62-41f5-94c6-37d47939ae85.jsonl new file mode 100644 index 0000000..40540f4 --- /dev/null +++ b/.omc/state/agent-replay-572cfe5e-cb62-41f5-94c6-37d47939ae85.jsonl @@ -0,0 +1,2 @@ +{"t":0,"agent":"a567d02","agent_type":"unknown","event":"agent_stop","success":true} +{"t":0,"agent":"a6f63da","agent_type":"unknown","event":"agent_stop","success":true} diff --git a/.omc/state/agent-replay-6febdf1e-2a69-4d80-9414-3d6b712b25bb.jsonl b/.omc/state/agent-replay-6febdf1e-2a69-4d80-9414-3d6b712b25bb.jsonl new file mode 100644 index 0000000..84ead65 --- /dev/null +++ b/.omc/state/agent-replay-6febdf1e-2a69-4d80-9414-3d6b712b25bb.jsonl @@ -0,0 +1,7 @@ +{"t":0,"agent":"aa3c21d","agent_type":"unknown","event":"agent_stop","success":true} +{"t":0,"agent":"a13b2eb","agent_type":"unknown","event":"agent_stop","success":true} +{"t":0,"agent":"a791a1b","agent_type":"unknown","event":"agent_stop","success":true} +{"t":0,"agent":"a70151c","agent_type":"unknown","event":"agent_stop","success":true} +{"t":0,"agent":"a488f88","agent_type":"unknown","event":"agent_stop","success":true} +{"t":0,"agent":"a588376","agent_type":"unknown","event":"agent_stop","success":true} +{"t":0,"agent":"a0e7cd4","agent_type":"unknown","event":"agent_stop","success":true} diff --git a/.omc/state/agent-replay-75102ef7-4cd7-4718-9d06-7626a28bbcb8.jsonl b/.omc/state/agent-replay-75102ef7-4cd7-4718-9d06-7626a28bbcb8.jsonl new file mode 100644 index 0000000..3c8f5b2 --- /dev/null +++ b/.omc/state/agent-replay-75102ef7-4cd7-4718-9d06-7626a28bbcb8.jsonl @@ -0,0 +1,4 @@ +{"t":0,"agent":"a04e80e","agent_type":"unknown","event":"agent_stop","success":true} +{"t":0,"agent":"a9b9f24","agent_type":"explore","event":"agent_start","parent_mode":"none"} +{"t":0,"agent":"a9b9f24","agent_type":"explore","event":"agent_stop","success":true,"duration_ms":60625} +{"t":0,"agent":"a895674","agent_type":"unknown","event":"agent_stop","success":true} diff --git a/.omc/state/agent-replay-992dcc72-e1e5-437a-b3b6-a3f8c693f1ec.jsonl b/.omc/state/agent-replay-992dcc72-e1e5-437a-b3b6-a3f8c693f1ec.jsonl new file mode 100644 index 0000000..0902c45 --- /dev/null +++ b/.omc/state/agent-replay-992dcc72-e1e5-437a-b3b6-a3f8c693f1ec.jsonl @@ -0,0 +1 @@ +{"t":0,"agent":"af530c0","agent_type":"unknown","event":"agent_stop","success":true} diff --git a/.omc/state/agent-replay-bcdd4855-a518-4baf-9564-127b3a79d3f7.jsonl b/.omc/state/agent-replay-bcdd4855-a518-4baf-9564-127b3a79d3f7.jsonl new file mode 100644 index 0000000..48c8616 --- /dev/null +++ b/.omc/state/agent-replay-bcdd4855-a518-4baf-9564-127b3a79d3f7.jsonl @@ -0,0 +1,4 @@ +{"t":0,"agent":"aaa41bb","agent_type":"unknown","event":"agent_stop","success":true} +{"t":0,"agent":"system","event":"skill_invoked","skill_name":"find-skills"} +{"t":0,"agent":"aa7d07a","agent_type":"unknown","event":"agent_stop","success":true} +{"t":0,"agent":"a604ba3","agent_type":"unknown","event":"agent_stop","success":true} diff --git a/.omc/state/agent-replay-cb8f78c9-4c40-4e6a-bd70-ba499b555d40.jsonl b/.omc/state/agent-replay-cb8f78c9-4c40-4e6a-bd70-ba499b555d40.jsonl new file mode 100644 index 0000000..4b2fd73 --- /dev/null +++ b/.omc/state/agent-replay-cb8f78c9-4c40-4e6a-bd70-ba499b555d40.jsonl @@ -0,0 +1,2 @@ +{"t":0,"agent":"system","event":"skill_invoked","skill_name":"oh-my-claudecode:hud"} +{"t":0,"agent":"afab084","agent_type":"unknown","event":"agent_stop","success":true} diff --git a/.omc/state/hud-state.json b/.omc/state/hud-state.json new file mode 100644 index 0000000..e1d9b90 --- /dev/null +++ b/.omc/state/hud-state.json @@ -0,0 +1,6 @@ +{ + "timestamp": "2026-02-20T13:40:21.901Z", + "backgroundTasks": [], + "sessionStartTimestamp": "2026-02-20T12:55:14.824Z", + "sessionId": "f1da58ef16330f2a" +} \ No newline at end of file diff --git a/.omc/state/subagent-tracking.json b/.omc/state/subagent-tracking.json new file mode 100644 index 0000000..cc8c980 --- /dev/null +++ b/.omc/state/subagent-tracking.json @@ -0,0 +1,17 @@ +{ + "agents": [ + { + "agent_id": "a9b9f24", + "agent_type": "oh-my-claudecode:explore", + "started_at": "2026-02-20T13:10:01.740Z", + "parent_mode": "none", + "status": "completed", + "completed_at": "2026-02-20T13:11:02.365Z", + "duration_ms": 60625 + } + ], + "total_spawned": 1, + "total_completed": 1, + "total_failed": 0, + "last_updated": "2026-02-20T13:47:26.026Z" +} \ No newline at end of file diff --git a/.sisyphus/plans/tag-merge-n8n.md b/.sisyphus/plans/tag-merge-n8n.md new file mode 100644 index 0000000..3aa41bd --- /dev/null +++ b/.sisyphus/plans/tag-merge-n8n.md @@ -0,0 +1,281 @@ +# Tag Janitor: n8n 每日 AI 标签合并 + +## TL;DR + +目标:解决 AI 生成导致的“标签爆炸”,不改现有入库逻辑(允许自由生成 tags),通过 **n8n 每日任务**调用站点 API 自动做 **标签语义合并 + nameEn 补全**,并保证合并后项目仍正确绑定到新标签。 + +交付物: + +- 新增 tags 维护 API(list + maintenance/merge) +- n8n workflow(每日运行):拉取 tags → AI 产出合并计划/英文补全 → 调用 API 执行 → 输出日报 +- Vitest 自动化测试(route + 核心 merge 逻辑) + +--- + +## Context + +### 现状(已验证) + +- Tag 数据模型:`prisma/schema.prisma`(`Tag` + `ProjectTag`) + - `Tag.name` 全局唯一,`Tag.slug` 全局唯一,`Tag.nameEn` 可空,`Tag.createdAt` 存在 + - `ProjectTag` 复合主键 `@@id([projectId, tagId])`(同一项目不能重复绑定同一 tag) +- Tag 入库: + - Webhook:`src/app/api/webhook/projects/route.ts`(批量 upsert tags;使用 `generateSlug()`;存在 slug 冲突兜底) + - Discovery:`src/app/api/discovery/lib/discovery-service.ts`(`upsertTags()` 与 webhook 类似) +- UI 过滤: + - 项目列表按 `tag slug` 过滤:`src/hooks/useProjects.ts`(`where.tags.some.tag.slug = tag`) + - TagCloud 搜索大小写不敏感,但展示/过滤依赖 slug:`src/components/project/TagCloud.tsx` +- Slug 生成:`src/lib/slug.ts`(优先 nameEn,否则 name;lowercase;保留中文;空格→-;最长 100) + +### 约束与偏好(用户确认) + +- 不做复杂治理:无审核 UI、无回滚系统、无 alias/redirect 层、无 merge memory。 +- 合并后旧标签直接删除。 +- 新项目入库仍可自由生成 tags(不做入库侧规范化/映射),一切靠每日合并流程兜底。 +- 标签双语:需要 `name` + `nameEn`(可相同,例如 Python)。 +- AI 判定逻辑放在 n8n;站点 API 只负责“安全执行合并”。 +- 需要自动化测试(Vitest)。 + +--- + +## 关键设计(最小可用) + +### 1) API 只做“合并执行器” + +站点侧不做语义判断、不接 embedding、不做候选生成;只接收 n8n 给出的“合并计划”,并以 Prisma 事务保证一致性。 + +必须满足: + +- 合并后 `ProjectTag` 绑定迁移完成(不会丢失项目-标签关系) +- 避免因 `@@id([projectId, tagId])` 造成重复冲突(迁移时要去重) +- 执行完删除旧 tags(source tags) +- 合并完触发缓存更新(ISR)以尽快反映 tag counts + +### 2) n8n 负责 AI:语义聚类 + 合并计划 + nameEn 补全 + +最简单闭环: + +- 每日拉取全量 tags(含 projectCount) +- 让 LLM 输出: + - merges:[{ target: {name, nameEn}, sourceTagIds: [...] }] + - updates:[{ tagId, nameEn }] +- 调用 API 执行 merges/updates +- 输出日报(合并数量、删除 tags 数、nameEn 补全数、失败明细) + +--- + +## 默认策略(无须再问用户) + +- 旧 slug 不做重定向:合并后如果用户用旧 `?tag=oldSlug` 访问,页面会显示 0 结果(符合“不要复杂化”的约束)。 +- Merge 过程中不强制改动 `slug`: + - 对“新建 canonical tag”由 API 按 `generateSlug(name, nameEn)` 生成 slug + - 对“复用已有 tagId 作为 target”不强制改 slug(避免破坏既有链接);只更新 `name/nameEn`(如果 n8n 传了) +- API 鉴权复用 `WEBHOOK_API_KEY`(与 `src/app/api/webhook/projects/route.ts` 同一密钥),用 `crypto.timingSafeEqual()`。 + +--- + +## Execution Strategy (Waves) + +Wave 1 (Design + Audit) + +- Task 1: 明确 API contract(list + maintenance)+ 错误码 +- Task 2: 设计 n8n workflow(节点、prompt、chunking、重试策略) + +Wave 2 (Backend Implementation) + +- Task 3: 新增 tags list API(给 n8n 拉取 tags + counts) +- Task 4: 新增 tags maintenance API(merges + updates;事务;去重;删除旧 tag) +- Task 5: 触发 ISR revalidate(项目列表页) + +Wave 3 (Automation + Tests) + +- Task 6: 写 Vitest 测试(route + merge 逻辑) +- Task 7: 搭建 n8n workflow 并做一次 dry run + 一次真实合并 + +Critical Path: Task 1 → Task 4 → Task 6 → Task 7 + +--- + +## TODOs + +### 1) 定义 API Contract(list + maintenance) + +**What to do**: + +- 设计 2 个 endpoint: + - `GET /api/tags`:返回 tags 列表(id/name/nameEn/slug/createdAt/\_count.projects) + - `POST /api/tags/maintenance`:鉴权 + 批量执行 `updates` 与 `merges` +- 约定响应结构:`{ success: boolean, ... }`,失败时带 `error` + `details` + +**Must NOT do**: + +- 不引入 alias/redirect +- 不引入 merge history/回滚 + +**References**: + +- `prisma/schema.prisma` - `Tag`/`ProjectTag` 约束(unique/复合主键) +- `src/app/api/webhook/projects/route.ts` - API key 鉴权 + Zod safeParse + 返回结构风格 +- `src/lib/validations.ts` - Zod schema 放置位置/风格 + +**Acceptance Criteria**: + +- 产出一个明确的 JSON schema(写进实现用的 Zod schema),覆盖:空 merges、重复 tagId、自合并、无效 tagId、nameEn 缺失。 + +--- + +### 2) 设计 n8n 每日 Tag Janitor Workflow + +**What to do**: + +- 节点建议:Cron → HTTP(GET /api/tags) → Code(预处理/分块) → LLM(生成 merges+updates) → Code(JSON 校验/拆批) → HTTP(POST /api/tags/maintenance) → 汇总通知 +- Prompt 输出必须是严格 JSON(避免解析失败) +- 需要考虑 LLM 输入过大时的分块策略(按字母/按 projectCount/按 createdAt) + +**Must NOT do**: + +- 不要求人工审核 + +**References**: + +- `src/hooks/useProjects.ts` - tags 的 `_count.projects` 查询方式(作为 /api/tags 的实现依据) +- `src/components/project/TagCloud.tsx` - UI 依赖 slug(理解合并后旧 slug 失效的表现) + +**Acceptance Criteria**: + +- n8n workflow 最终只依赖两个站点接口(GET /api/tags, POST /api/tags/maintenance) +- LLM 输出 JSON 包含:`merges`(数组)与 `updates`(数组) + +--- + +### 3) 实现 `GET /api/tags` + +**What to do**: + +- 新增 route:`src/app/api/tags/route.ts`(实现 GET) +- 用 Prisma 查询 Tag 并 include `_count.projects` + +**References**: + +- `src/hooks/useProjects.ts` - `getAllTags()` 的 Prisma 查询(可直接复用/抽成共享函数) + +**Acceptance Criteria (agent-executable)**: + +```bash +curl -s http://localhost:3000/api/tags | jq '.success' +# Assert: true + +curl -s http://localhost:3000/api/tags | jq '.tags[0] | has("id") and has("slug") and has("_count")' +# Assert: true +``` + +--- + +### 4) 实现 `POST /api/tags/maintenance`(updates + merges) + +**What to do**: + +- 新增 route:`src/app/api/tags/maintenance/route.ts`(实现 POST) +- 鉴权:复用 `WEBHOOK_API_KEY` + `crypto.timingSafeEqual()`(参考 webhook) +- Zod 校验请求体 +- Prisma 事务执行: + 1. 执行 `updates`(主要是 nameEn 补全;允许 name/nameEn 相同) + 2. 执行 `merges` + - target tag:若 n8n 给的是 id → 使用;若给的是 name/nameEn → upsert/create(slug 用 `generateSlug()`) + - 迁移 `ProjectTag`:把 sourceTagIds 关联的 projectId 迁移到 targetTagId(需去重,避免复合主键冲突) + - 删除 source tags(`Tag` 记录) + 3. 结束后 revalidate 相关路径 + +**References**: + +- `prisma/schema.prisma` - `ProjectTag` 复合主键导致去重需求 +- `src/lib/slug.ts` - `generateSlug()` +- `src/app/api/webhook/projects/route.ts` - `timingSafeEqual` 鉴权与错误返回格式 + +**Acceptance Criteria (agent-executable)**: + +```bash +# 1) 未授权 +curl -s -X POST http://localhost:3000/api/tags/maintenance \ + -H 'Content-Type: application/json' \ + -d '{"updates":[],"merges":[]}' \ + | jq '.error' +# Assert: "Unauthorized" (or equivalent) + +# 2) 授权空操作成功 +curl -s -X POST http://localhost:3000/api/tags/maintenance \ + -H 'Content-Type: application/json' \ + -d '{"apiKey":"'"$WEBHOOK_API_KEY"'","updates":[],"merges":[]}' \ + | jq '.success' +# Assert: true +``` + +--- + +### 5) ISR/缓存刷新策略 + +**What to do**: + +- 在 maintenance 成功后调用 `revalidatePath()` 刷新 projects 列表页(至少 `/{locale}/projects` 对应的路径) + +**References**: + +- `src/hooks/AGENTS.md` - 建议在数据更新后使用 `revalidatePath()` + +**Acceptance Criteria**: + +- 合并后 1 次刷新内(无需等待 5 分钟)能看到 tags count 变化(用 Playwright 或 curl + 页面渲染断言)。 + +--- + +### 6) Vitest 测试(route + merge 逻辑) + +**What to do**: + +- 新增测试文件(参考风格):`src/app/api/events/route.test.ts` +- 至少覆盖: + - 未授权 401 + - body schema 校验失败 400 + - 合并执行时: + - 迁移 projectTag 去重逻辑不会抛错 + - source tag 会被删除 + - target tag 的 nameEn 会被补全/更新 + +**References**: + +- `src/app/api/events/route.test.ts` - NextRequest 调用 route handler 的测试方式 + +**Acceptance Criteria (agent-executable)**: + +```bash +pnpm test +# Assert: exit code 0 +``` + +--- + +### 7) n8n Workflow 落地与一次端到端验证 + +**What to do**: + +- 在 n8n 中配置: + - 站点 baseUrl + - `WEBHOOK_API_KEY` + - LLM 凭证 +- 先 dry-run(只输出 merges/updates,不调用 maintenance) +- 再 real-run(调用 maintenance) + +**Acceptance Criteria (agent-executable)**: + +- 运行一次后: + - `/api/tags` 返回的 tag 总数下降(或至少不增长) + - 采样 1-2 个被合并的 source tag,其 slug 再用于 `/{locale}/projects?tag=` 时返回 0 项(可接受) + - 被合并的项目在新 canonical tag slug 下能被筛出来(`src/hooks/useProjects.ts` 的 tag filter 生效) + +--- + +## Notes / Gotchas + +- `Tag.name` 与 `Tag.slug` 均为唯一:当 AI 生成 canonical 名称时,可能撞车;API 需要在创建/更新时处理并返回可读错误(让 n8n 重试或改名)。 +- 合并迁移时必须去重:`ProjectTag` 的 `@@id([projectId, tagId])` 会在“同一项目已拥有 target tag”时导致冲突。 +- 如果未来 tag 规模增大,n8n 端需要升级候选生成(先 lexical/embedding 粗筛,再让 LLM 决策)。本计划先按“规模尚可”实现全量日更。 diff --git a/AGENTS.md b/AGENTS.md index 9250bee..13382cb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,12 +1,12 @@ # PROJECT KNOWLEDGE BASE -**Generated:** 2026-02-01 +**Generated:** 2026-02-01 | **Updated:** 2026-02-20 **Commit:** N/A (new generation) **Branch:** main ## OVERVIEW -Next.js 15 multilingual AI project navigation website with App Router, TypeScript, Prisma ORM, and Tailwind CSS neo-brutalism design. Features automated project discovery and quarterly AI keyword cloud system. +Next.js 15 multilingual AI project navigation website with App Router, TypeScript, Prisma ORM, and Tailwind CSS neo-brutalism design. Features automated project discovery, quarterly AI keyword cloud system, and AI Timeline historical events. ## STRUCTURE @@ -256,3 +256,41 @@ pnpm prisma studio # Database inspector - **src/components/**: Neo-brutalism design system, component organization (see `src/components/AGENTS.md`) - **src/lib/**: Validation layer, utilities, GitHub integration (see `src/lib/AGENTS.md`) - **src/hooks/**: Server-side data fetching, query optimization (see `src/hooks/AGENTS.md`) + +## N8N PRODUCTION WORKFLOWS + +Production workflows tagged with "生产" in n8n instance: + +| Workflow | Status | Nodes | Purpose | +|----------|--------|-------|---------| +| 项目描述向量化 | ✅ Active | 11 | Generate embeddings for project descriptions (RAG) | +| Github项目分析入库 | ⏸️ Inactive | 16 | Analyze GitHub repos and ingest into database | +| RAG项目搜索 | ✅ Active | 6 | AI-powered project search using vector similarity | +| 每日Github Trending项目计划新增 | ✅ Active | 17 | Daily trending repos → discovery tasks | +| Topic项目计划新增 | ⏸️ Inactive | 16 | Topic-based project discovery tasks | + +### Workflow Data Flow + +``` +GitHub Trending/Topic → Discovery Tasks (PENDING) + ↓ + Content Explorer Agent + ↓ + Project Ingestion API + ↓ + 向量化 Workflow → Embeddings + ↓ + RAG项目搜索 ← User Query +``` + +## AI TIMELINE SYSTEM + +Historical AI events tracking system: + +- **Model**: `AIEvent` in `prisma/schema.prisma` +- **Fields**: title/titleEn, eventDate, description/descriptionEn, imageUrl, sourceUrl +- **API**: `src/app/api/events/route.ts` +- **Frontend**: `src/app/[locale]/timeline/` +- **Index**: `eventDate` (descending) for chronological queries + + diff --git a/docs/AGENTS.md b/docs/AGENTS.md new file mode 100644 index 0000000..f04ef0a --- /dev/null +++ b/docs/AGENTS.md @@ -0,0 +1,55 @@ +# docs/ - Project Documentation + + + +## OVERVIEW + +Technical documentation, design plans, and implementation guides for the agent_park project. + +## STRUCTURE + +``` +docs/ +├── api-reference.md # API endpoint documentation +├── api-testing-guide.md # API testing instructions +├── discovery-workflow.md # Project discovery system docs +├── e2e-testing-guide.md # Playwright E2E guide +├── verification-report.md # Feature verification reports +├── analyst.md # Product analysis notes +├── n8n/ # n8n workflow documentation +│ ├── historical-workflow-design.md +│ ├── incremental-workflow-design.md +│ └── tag-janitor-workflow.md +└── plans/ # Design & implementation plans + ├── 2026-01-25-ai-search-system-design.md + ├── 2026-01-25-ai-search-implementation.md + ├── 2025-01-25-ai-timeline-feature-design.md + ├── 2025-01-25-ai-timeline-implementation.md + ├── 2026-01-25-keyword-cloud-system-design.md + └── 2026-01-25-keyword-cloud-implementation.md +``` + +## KEY DOCUMENTS + +| Document | Purpose | +|----------|---------| +| `api-reference.md` | Complete API documentation | +| `discovery-workflow.md` | Project discovery architecture | +| `plans/*.md` | Feature design & implementation specs | +| `n8n/*.md` | n8n workflow design docs | + +## FOR AI AGENTS + +### When Adding Documentation + +1. Place design docs in `plans/` with date prefix +2. Update this AGENTS.md with new file entries +3. Follow existing markdown formatting + +### Related Files + +- `CLAUDE.md` - Main project context (root) +- `AGENTS.md` - Project knowledge base (root) +- `.claude/` - Custom agents & commands + + diff --git a/docs/analyst.md b/docs/analyst.md new file mode 100644 index 0000000..e62f4b8 --- /dev/null +++ b/docs/analyst.md @@ -0,0 +1,158 @@ +--- + +## 🎯 现状问题诊断 + +### 1. 信息架构问题 +- **标签体系混乱**:有的项目标了"本地部署/macOS/iOS/Android"(4个标签),有的只有"✨",标准不统一 +- **缺乏分类维度**:用户无法快速筛选"开源/闭源"、"可商用/个人项目"、"多智能体/单智能体" +- **没有时间维度**:看不出项目是新发布还是经典项目,对 Agent 这个快速迭代的领域很关键 + +### 2. 用户体验断层 +- **卡片信息过载/不足并存**:描述长短不一,但缺少关键决策信息(GitHub stars?是否开源?演示链接?) +- **无快速筛选**:当项目超过20个时,浏览成本会指数级上升 +- **缺乏"为什么值得关注"**:单纯罗列不如策展(Curation),需要策展人视角的推荐理由 + +### 3. 技术呈现问题 +- **移动端适配**:从代码结构看是响应式,但卡片在手机上可能过于拥挤 +- **无暗色模式**:开发者群体对暗色模式有强需求,实现成本低(CSS media query) +- **加载性能**:如果 n8n 工作流生成的是静态 Markdown,建议预渲染为 HTML 提升首屏速度 + +--- + +## 💡 轻量级但高价值的功能设计 + +基于"不做重,但要做巧"的原则,推荐以下功能: + +### 阶段一:核心体验完善(2周内) + +**1. 极简标签系统(三层维度)** +``` +类型标签:🤖 Chatbot | 🔄 Multi-Agent | 🧠 Memory | 👁️ Vision | 🛠️ Tool Use +形态标签:📦 开源 | ☁️ SaaS | 💻 本地部署 | 📱 App +热度标签:🔥 Trending | ⭐ Classic | 🆕 New +``` +*实现:纯 CSS 过滤,无需后端,前端 JS 筛选即可* + +**2. "30秒决策"信息卡片** +每个项目卡片补充3个关键字段(n8n工作流抓取时补充): +- **GitHub Stars**(如果是开源) +- **体验方式**:Live Demo / 下载 / 仅代码 +- **适用场景**:一句话场景(如"适合搭建个人知识库") + +**3. 每日/每周精选(Newsletter 化)** +不增加功能,而是**内容运营策略**: +- 首页顶部固定"本周编辑推荐"(3个项目+一句话推荐理由) +- 底部增加邮件订阅框(用 Buttondown 或 Revue,零成本) +- 归档页面按周聚合(`/week-04-2025`) + +### 阶段二:社区感与互动(1个月内) + +**4. "使用报告"轻互动** +不同于评论系统(太重),采用**投票+标签**: +- "你在用吗?" 👍 / 👎(匿名) +- "适用场景"多选标签(用户可添加,类似 StackOverflow 的标签系统) +- 数据存储:Airtable 或 Notion API(轻量级数据库) + +**5. Agent 项目 Twitter 趋势墙** +无需自己生成内容,聚合展示: +- 嵌入 Twitter List(创建一个"Agent Builders"列表) +- 或展示特定 hashtag(如 `#AIAgent`)的最新热门推文 +- 实现:Twitter 嵌入式时间线,零维护成本 + +**6. 极简提交表单优化** +当前"立即提交"大概率跳转到表单,优化为: +- 预填项目模板(GitHub URL 自动抓取信息) +- 支持提交者写"推荐语"(策展人视角) +- 审核流:GitHub Issues 或 Airtable 表单(不用开发后台) + +### 阶段三:开发者工具化(2个月内) + +**7. Agent 项目 RSS 聚合** +开发者刚需:一站式追踪所有 Agent 项目更新 +- 为每个项目生成 RSS 源监控(GitHub releases) +- 提供聚合 RSS(用户订阅一个即可看全站更新) +- 技术:RSSHub 或 n8n 自动生成 + +**8. "Agent 构建模式"分类** +垂直领域细分(这是你的差异化): +- **ReAct 模式**项目集合 +- **Plan-and-Execute**项目 +- **Multi-Agent 协作框架** +- **Function Calling 工具库** +帮助开发者按技术方案选型,而非只看功能。 + +--- + +## 📋 分阶段实施计划( Roadmap ) + +### Week 1-2:基础优化 +- [ ] 统一标签体系(3层9个标签以内) +- [ ] 修改项目卡片模板(增加 Stars/Demo 链接字段) +- [ ] 增加暗色模式(`prefers-color-scheme` 媒体查询) +- [ ] 优化移动端卡片布局(单列+横向滚动标签) + +### Week 3-4:内容运营 +- [ ] 建立编辑推荐机制(每周手动精选3个) +- [ ] 上线邮件订阅(嵌入 Buttondown) +- [ ] 优化提交表单(GitHub URL 自动拉取) +- [ ] 创建 Twitter/X 账号同步发布精选 + +### Month 2:互动功能 +- [ ] 增加轻量级投票系统(用 Upstash Redis 或 Airtable) +- [ ] 上线 RSS 订阅功能 +- [ ] 增加"技术模式"分类维度 +- [ ] 发布首份《Agent Landscape 月报》(PDF 轻量报告) + +### Month 3:生态扩展 +- [ ] 推出"Agent Builder 访谈"(轻量级文字访谈,每月2期) +- [ ] 建立 Discord/Telegram 群组(社区沉淀) +- [ ] 尝试"项目雷达"功能(预测下周可能火的项目) + +--- + +## 💰 变现可能性分析(从轻到重) + +基于"保持轻量"的前提,按可行性排序: + +### 1. **策展付费(轻量,推荐优先尝试)** +- **模式**:每周付费 Newsletter($5/月或$50/年),提供更深度的项目分析、代码解读、创始人访谈 +- **可行性**:⭐⭐⭐⭐⭐ 你已经用 n8n 做内容聚合,增加深度分析即可,无需改技术架构 +- **受众**:Agent 开发者愿意为高质量信息付费,参考 Lenny's Newsletter(产品经理领域) + +### 2. **精准职位板(轻量)** +- **模式**:"Agent 相关岗位"板块,公司付费发帖($100/月) +- **可行性**:⭐⭐⭐⭐ 当下 Agent 工程师需求旺盛,但供给分散,你的受众正是招聘方想要的 +- **优势**:比大型招聘站更精准,比 LinkedIn 更垂直 + +### 3. **开源项目赞助分成(超轻量)** +- **模式**:项目卡片增加"赞助该项目"按钮,跳转 GitHub Sponsors,你收取 5-10% 导流费或获得 affiliate 返点 +- **可行性**:⭐⭐⭐ 需要与项目方谈合作,但初期可以作为增值服务免费提供,建立信任后变现 + +### 4. **轻量级广告/赞助(需谨慎)** +- **模式**:接受 Agent 框架、云服务(如 LangSmith、Langfuse)的广告位 +- **可行性**:⭐⭐⭐ 需要流量基础(月UV 1万+),且要保持克制避免破坏体验 +- **建议**:以"赞助商推荐"形式融入内容,而非 banner 广告 + +### 5. **数据/洞察服务(未来方向)** +- **模式**:出售 Agent 趋势数据报告(GitHub 增长趋势、技术栈迁移方向) +- **可行性**:⭐⭐ 需要积累 6-12 个月数据,且需要品牌背书 +- **风险**:会变重,建议保持轻量,只出季度免费报告建立权威性 + +### ❌ 不建议的变现方式 +- **付费墙阻断访问**:违背导航站开放属性 +- **复杂的会员系统**:开发与维护成本高 +- **交易佣金**:涉及支付、合规,太重 + +--- + +## 🚀 立即可做的3个改动(本周) + +如果你只想快速优化,先做这三件: + +1. **标签标准化**:删除所有重复/冗长标签,只用 类型+形态 二维(如 `🤖Chatbot` `📦开源`) +2. **增加"一键体验"按钮**:在卡片上直接放 🔗Demo 或 💻GitHub 图标,减少用户点击成本 +3. **顶部增加时间线**:小字标注"本周新增 X 个项目,共收录 Y 个",营造更新感 + +**核心建议**:Agent Park 现在的定位应该是 **"Agent 爱好者的 Hacker News + Product Hunt 混合体"**,保持策展人(Curator)视角比做全量数据库更有价值。你的 n8n 工作流是护城河,但**人工精选的品味**才是核心竞争力。 + +需要我针对某个具体功能(比如 n8n 工作流优化方案、暗色模式 CSS、或者邮件订阅文案)展开详细方案吗? \ No newline at end of file diff --git a/n8n-workflows/AGENTS.md b/n8n-workflows/AGENTS.md new file mode 100644 index 0000000..c50f6e6 --- /dev/null +++ b/n8n-workflows/AGENTS.md @@ -0,0 +1,63 @@ +# n8n-workflows/ - Automation Workflows + + + +## OVERVIEW + +n8n workflow definitions for automated data collection, project discovery, and keyword cloud generation. Workflows sync with production n8n instance. + +## KEY FILES + +| File | Purpose | +|------|---------| +| `keyword-cloud-workflow.json` | Google Trends → Keywords API | +| `README.md` | Workflow documentation | + +## PRODUCTION WORKFLOWS (n8n Instance) + +| Workflow | Status | Nodes | Purpose | +|----------|--------|-------|---------| +| 项目描述向量化 | ✅ Active | 11 | Generate project embeddings for RAG | +| Github项目分析入库 | ⏸️ Inactive | 16 | Analyze & ingest GitHub repos | +| RAG项目搜索 | ✅ Active | 6 | AI-powered vector search | +| 每日Github Trending项目计划新增 | ✅ Active | 17 | Daily trending → discovery tasks | +| Topic项目计划新增 | ⏸️ Inactive | 16 | Topic-based discovery | + +## DATA FLOW + +``` +GitHub Trending API + ↓ +每日Github Trending项目计划新增 + ↓ +ProjectDiscoveryTask (PENDING) + ↓ +Content Explorer Agent (Claude) + ↓ +Project Ingestion API + ↓ +项目描述向量化 → Embeddings (pgvector) + ↓ +RAG项目搜索 ← User Query +``` + +## FOR AI AGENTS + +### When Modifying Workflows + +1. Export from n8n UI → update JSON file +2. Document changes in README.md +3. Test with n8n-mcp tools before production + +### Related API Endpoints + +- `POST /api/discovery/tasks` - Create discovery tasks +- `POST /api/keyword-cloud/keywords` - Bulk keyword upload +- `PATCH /api/tags/maintenance` - Tag cleanup (n8n integration) + +### Environment Variables (n8n) + +- `API_URL` - Production API endpoint +- `API_KEY` - Same as `WEBHOOK_API_KEY` + + diff --git a/prisma/AGENTS.md b/prisma/AGENTS.md new file mode 100644 index 0000000..b710910 --- /dev/null +++ b/prisma/AGENTS.md @@ -0,0 +1,128 @@ +# prisma/ - Database Layer + + + +## OVERVIEW + +Prisma ORM configuration for PostgreSQL (Neon serverless) with multilingual support, vector embeddings, and automated workflows integration. + +## KEY FILES + +| File | Purpose | +|------|---------| +| `schema.prisma` | Database models, enums, indexes | +| `seed.ts` | Initial data seeding script | +| `migrations/` | Migration history | + +## DATABASE MODELS + +### Core Models + +| Model | Purpose | Key Fields | +|-------|---------|------------| +| `Project` | AI projects | name/nameEn, slug (unique), description, content, embedding (vector) | +| `Tag` | Project tags | name (unique), slug (unique) | +| `ExternalLink` | Project links | type (WEBSITE/GITHUB/HUGGINGFACE/PAPER), url | +| `ProjectTag` | Junction table | projectId, tagId | + +### Keyword Cloud System + +| Model | Purpose | +|-------|---------| +| `Quarter` | Quarterly metadata | +| `Keyword` | Trending keywords with visual config | +| `VisualStyleRule` | Color/size/border rules by score range | +| `KeywordCloudErrorLog` | Error tracking for n8n workflows | + +### Discovery System + +| Model | Purpose | +|-------|---------| +| `ProjectDiscoveryTask` | Exploration task tracking | + +### AI Timeline System + +| Model | Purpose | +|-------|---------| +| `AIEvent` | Historical AI events with dates | + +## ENUMS + +- `ProjectStatus`: ACTIVE | ARCHIVED +- `LinkType`: WEBSITE | GITHUB | HUGGINGFACE | PAPER +- `TaskStatus`: PENDING | IN_PROGRESS | COMPLETED | FAILED + +## INDEXES + +| Index | Model | Purpose | +|-------|-------|---------| +| `idx_project_slug` | Project | Unique slug lookup | +| `idx_project_status_createdAt` | Project | Filter by status, sort by date | +| `idx_project_embedding_cosine` | Project | Vector similarity search | +| `idx_link_type_url` | ExternalLink | URL deduplication | +| `idx_task_status_created` | ProjectDiscoveryTask | Task queue queries | +| `idx_keyword_quarterId` | Keyword | Quarterly keyword lookup | +| `idx_quarter_displayOrder` | Quarter | Quarter ordering | + +## MULTILINGUAL PATTERN + +Most models follow the dual-language pattern: +``` +name: String // Chinese (primary) +nameEn: String? // English (optional) + +description: String +descriptionEn: String? + +content: String? +contentEn: String? +``` + +## CASCADE DELETIONS + +- `ExternalLink` → `Project` (onDelete: Cascade) +- `ProjectTag` → `Project` and `Tag` (onDelete: Cascade) +- `Keyword` → `Quarter` (onDelete: Cascade) + +## FOR AI AGENTS + +### Working With This Directory + +1. **After schema changes**: + ```bash + pnpm prisma migrate dev --name description + pnpm prisma generate + ``` + +2. **Seed database**: + ```bash + pnpm prisma db seed + ``` + +3. **Inspect database**: + ```bash + pnpm prisma studio + ``` + +### Common Patterns + +- **Unique constraints**: Handle with try-catch + fallback (see webhook tag upsert) +- **Multilingual queries**: Always check both `field` and `fieldEn` variants +- **Vector search**: Use `Unsupported("vector")` type with pgvector extension + +### Anti-Patterns + +- NEVER modify schema without running migrations +- NEVER skip `pnpm prisma generate` after schema changes +- NEVER use raw SQL when Prisma methods are available +- NEVER commit `.env` files with DATABASE_URL + +## N8N INTEGRATION + +n8n workflows interact with these models: +- **Keywords**: Written by keyword-cloud workflow +- **ProjectDiscoveryTask**: Created by trending/topic workflows +- **Project**: Updated by analysis workflows +- **Tag**: Maintained by tag-janitor workflow + + diff --git a/project-structure.txt b/project-structure.txt new file mode 100644 index 0000000..4e00336 --- /dev/null +++ b/project-structure.txt @@ -0,0 +1,148 @@ +# 项目目录结构 + +## 📁 根目录结构 + +### 🎯 主要源代码目录 +``` +src/ +├── app/ # Next.js App Router (核心应用) +│ ├── [locale]/ # 国际化路由 +│ │ ├── keyword-cloud/ # 词云功能页面 +│ │ ├── projects/ # 项目页面 +│ │ └── timeline/ # 时间线功能页面 +│ └── api/ # API 路由 +│ ├── discovery/ # 项目发现 API +│ ├── events/ # 事件 API +│ ├── keyword-cloud/ # 词云 API +│ ├── projects/ # 项目 API +│ ├── search/ # 搜索 API +│ └── webhook/ # Webhook API +├── components/ # React 组件 +│ ├── layout/ # 布局组件 +│ ├── locale/ # 国际化组件 +│ ├── project/ # 项目相关组件 +│ ├── search/ # 搜索相关组件 +│ └── timeline/ # 时间线相关组件 +├── hooks/ # 服务端数据获取函数 +├── i18n/ # 国际化配置 +├── lib/ # 工具库 +│ └── github/ # GitHub 相关工具 +└── messages/ # 翻译文件 +``` + +### ⚙️ 配置文件 +``` +├── next.config.js # Next.js 配置 +├── tailwind.config.ts # Tailwind CSS 配置 +├── tsconfig.json # TypeScript 配置 +├── components.json # Radix UI 组件配置 +├── .eslintrc.json # ESLint 配置 +└── .prettierrc.json # Prettier 配置 +``` + +### 🗄️ 数据库配置 +``` +prisma/ +├── schema.prisma # 数据库模式 +└── migrations/ # 数据库迁移 +``` + +### 🔧 自定义 Agents +``` +.claude/ +└── agents/ # Claude Code 自定义 Agent +``` + +### 🔄 n8n 工作流 +``` +n8n-workflows/ +├── keyword-cloud-workflow.json # 词云采集工作流 +└── README.md # 工作流文档 + +docs/n8n/ +├── historical-workflow-design.md # 历史工作流设计 +├── incremental-workflow-design.md # 增量工作流设计 +└── tag-janitor-workflow.json # 标签清理工作流 +``` + +### 📚 文档 +``` +docs/ +├── api-reference.md # API 参考 +├── api-testing-guide.md # API 测试指南 +├── discovery-workflow.md # 项目发现工作流 +├── e2e-testing-guide.md # E2E 测试指南 +├── plans/ # 项目规划文档 +└── n8n/ # n8n 相关文档 +``` + +### 🎨 设计资源 +``` +design/ +├── hotpot cloud/ # Hotpot 云相关设计 +│ └── screen.png +└── timeline/ # 时间线设计 + └── screen.png +``` + +### 📜 数据库种子脚本 +``` +scripts/ +├── list-tags.js # 标签列表脚本 +├── seed-historical-events.ts # 历史事件种子数据 +├── seed-keyword-cloud.ts # 词云种子数据 +└── test-keyword-api.ts # 词云 API 测试 +``` + +### 🧪 测试 +``` +tests/ +└── screenshots/ # 截图测试 +``` + +### 🚀 其他配置 +``` +opencode/ # OpenCode 配置 +└── mcp.json # MCP 服务器配置 + +.env # 环境变量 +.env.example # 环境变量模板 +AGENTS.md # Agent 文档 +CLAUDE.md # 项目说明文档 +package.json # 项目依赖 +``` + +## 🎯 特殊功能目录 + +### 1. 项目发现系统 (Project Discovery) +- **位置**: `src/app/api/discovery/` +- **功能**: 自动化探索和收录 AI 项目 +- **特点**: 双 Agent 协作架构 + +### 2. 词云系统 (Keyword Cloud) +- **位置**: `src/app/[locale]/keyword-cloud/` 和 `src/app/api/keyword-cloud/` +- **功能**: 季度 AI 热点词云展示 +- **特点**: n8n 自动化采集、实时数据展示 + +### 3. 时间线系统 (Timeline) +- **位置**: `src/app/[locale]/timeline/` +- **功能**: AI 历史事件时间线 +- **特点**: 渐进式加载、历史事件展示 + +### 4. n8n 工作流 +- **位置**: `n8n-workflows/` 和 `docs/n8n/` +- **功能**: + - keyword-cloud-workflow.json: Google Trends 数据采集 + - tag-janitor-workflow.json: 标签清理自动化 +- **特点**: 季度触发、错误处理、API 集成 + +### 5. 项目管理系统 +- **位置**: `src/app/[locale]/projects/` 和 `src/app/api/projects/` +- **功能**: AI 项目展示、搜索、分类 +- **特点**: 多语言支持、标签系统、Webhook 集成 + +### 6. 搜索系统 +- **位置**: `src/app/api/search/` 和 `src/components/search/` +- **功能**: AI 项目搜索和过滤 +- **特点**: 多条件搜索、分页、状态过滤 +``` diff --git a/src/AGENTS.md b/src/AGENTS.md new file mode 100644 index 0000000..7a9f8ac --- /dev/null +++ b/src/AGENTS.md @@ -0,0 +1,47 @@ +# src/ - Source Code + + + +## OVERVIEW + +Application source code organized by Next.js 15 App Router conventions with internationalization support. + +## STRUCTURE + +``` +src/ +├── app/ # Next.js App Router (pages + API) +├── components/ # React components (neo-brutalism design) +├── hooks/ # Server-side data fetching (NOT React hooks) +├── lib/ # Utilities, validation, Prisma client +├── i18n/ # next-intl configuration +├── messages/ # Translation files (zh.json, en.json) +└── middleware.ts # Locale detection & routing +``` + +## KEY DIRECTORIES + +| Directory | Purpose | See | +|-----------|---------|-----| +| `app/` | App Router pages & API routes | `app/AGENTS.md` | +| `components/` | UI components by domain | `components/AGENTS.md` | +| `hooks/` | Server data fetching functions | `hooks/AGENTS.md` | +| `lib/` | Core utilities & validation | `lib/AGENTS.md` | + +## FOR AI AGENTS + +### When Adding New Features + +1. **Pages**: Add to `app/[locale]/` following locale pattern +2. **API**: Add to `app/api/` with Zod validation +3. **Components**: Add to appropriate domain folder +4. **Translations**: Update BOTH `zh.json` AND `en.json` + +### Common Patterns + +- **Locale routing**: `middleware.ts` handles locale detection +- **Data fetching**: Use functions from `hooks/` in Server Components +- **Validation**: All schemas in `lib/validations.ts` +- **Styling**: Neo-brutalism with Tailwind (see `components/AGENTS.md`) + + diff --git a/src/app/AGENTS.md b/src/app/AGENTS.md index 5c24028..8f4334b 100644 --- a/src/app/AGENTS.md +++ b/src/app/AGENTS.md @@ -1,16 +1,34 @@ # src/app/ - App Router Implementation + + ## OVERVIEW Next.js 15 App Router with next-intl locale routing and multilingual project discovery platform ## STRUCTURE -- `[locale]/` - Locale-scoped routes (zh/en), home, projects, keyword-cloud -- `api/` - API endpoints (webhook, discovery, keyword-cloud, search) +- `[locale]/` - Locale-scoped routes (zh/en), home, projects, keyword-cloud, timeline +- `api/` - API endpoints (webhook, discovery, keyword-cloud, search, events, tags) - `globals.css` - Tailwind + neo-brutalism styles - `layout.tsx` - Root layout +## KEY FILES + +| File | Purpose | +|------|---------| +| `[locale]/page.tsx` | Home page | +| `[locale]/projects/page.tsx` | Project listing | +| `[locale]/projects/[id]/page.tsx` | Project detail (ISR 5min) | +| `[locale]/keyword-cloud/page.tsx` | Quarterly keyword cloud | +| `[locale]/timeline/page.tsx` | AI historical events timeline | +| `api/webhook/projects/route.ts` | Project ingestion webhook | +| `api/discovery/tasks/route.ts` | Discovery task CRUD | +| `api/search/ai/route.ts` | AI-powered RAG search | +| `api/events/route.ts` | AI Timeline events API | +| `api/tags/route.ts` | Tags CRUD | +| `api/tags/maintenance/route.ts` | Tag cleanup (n8n integration) | + ## WHERE TO LOOK - **Locale routing**: `src/middleware.ts`, `src/app/[locale]/layout.tsx` diff --git a/src/components/AGENTS.md b/src/components/AGENTS.md index 7d426b4..a798af1 100644 --- a/src/components/AGENTS.md +++ b/src/components/AGENTS.md @@ -1,4 +1,6 @@ -# Component System Architecture +# src/components/ - Component System + + ## Neo-Brutalism Design Principles diff --git a/src/hooks/AGENTS.md b/src/hooks/AGENTS.md index 0b0c227..5fe66d7 100644 --- a/src/hooks/AGENTS.md +++ b/src/hooks/AGENTS.md @@ -1,5 +1,7 @@ # src/hooks/ - Server-Side Data Fetching + + **Purpose**: Server-side data fetching functions (NOT React hooks). Exported functions for use in Server Components and API routes. ## Architecture diff --git a/src/lib/AGENTS.md b/src/lib/AGENTS.md index 01e8e04..9907e90 100644 --- a/src/lib/AGENTS.md +++ b/src/lib/AGENTS.md @@ -1,5 +1,7 @@ # src/lib/ - Core Utilities + + ## Overview Shared utilities and infrastructure layers used across the application. diff --git a/tests/screenshots/timeline-fixed.png b/tests/screenshots/timeline-fixed.png deleted file mode 100644 index e669b0d..0000000 Binary files a/tests/screenshots/timeline-fixed.png and /dev/null differ diff --git a/tests/screenshots/timeline-hover.png b/tests/screenshots/timeline-hover.png deleted file mode 100644 index 9084ca0..0000000 Binary files a/tests/screenshots/timeline-hover.png and /dev/null differ diff --git a/tests/screenshots/timeline-page.png b/tests/screenshots/timeline-page.png deleted file mode 100644 index 6f385d5..0000000 Binary files a/tests/screenshots/timeline-page.png and /dev/null differ diff --git a/tests/screenshots/timeline-verified.png b/tests/screenshots/timeline-verified.png deleted file mode 100644 index 127ec4d..0000000 Binary files a/tests/screenshots/timeline-verified.png and /dev/null differ