Files
agent-park/CLAUDE.md
T

465 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Development Commands
### Build & Run
```bash
pnpm dev # Start development server (Next.js 15)
pnpm build # Build for production
pnpm start # Start production server
pnpm lint # Run ESLint
```
### Testing
```bash
pnpm test # Run Vitest unit tests
pnpm test:e2e # Run Playwright E2E tests
```
### Database
```bash
pnpm prisma migrate dev # Run database migrations
pnpm prisma migrate dev --name init # Create initial migration
pnpm prisma db seed # Seed database (uses ts-node)
pnpm prisma studio # Open Prisma Studio for database inspection
```
## Architecture Overview
This is a **Next.js 15 multilingual AI project navigation website** using the App Router architecture with the following key components:
### i18n Architecture (next-intl)
- **Locales**: `zh` (default) and `en`
- **Route pattern**: `/{locale}/path` (always prefixed with locale)
- **Middleware**: `src/middleware.ts` handles locale detection and routing
- **i18n config**: `src/i18n/request.ts` loads locale messages from `src/messages/{locale}.json`
- **Messages**: Translation files at `src/messages/zh.json` and `src/messages/en.json`
### App Router Structure
```
src/app/
├── [locale]/ # Locale-scoped routes
│ ├── page.tsx # Home page
│ ├── projects/ # Projects listing and details
│ │ ├── page.tsx # Projects list
│ │ └── [id]/ # Individual project details (slug-based)
│ └── layout.tsx # Locale layout (header, footer)
├── api/ # API routes (no locale prefix)
│ └── webhook/projects/route.ts # Webhook for project ingestion
└── layout.tsx # Root layout
```
### Database (Prisma + PostgreSQL)
- **Provider**: Neon (serverless PostgreSQL)
- **Schema**: `prisma/schema.prisma` defines models: `Project`, `Tag`, `ExternalLink`, `ProjectTag`
- **Enums**: `ProjectStatus` (ACTIVE/ARCHIVED), `LinkType` (WEBSITE/GITHUB/HUGGINGFACE/PAPER)
- **Client singleton**: `src/lib/prisma.ts` exports Prisma client instance
- **Multilingual fields**: Most models have `name`/`nameEn`, `description`/`descriptionEn`, `content`/`contentEn` pairs
- **Cascade deletions**: `ExternalLink` and `ProjectTag` use `onDelete: Cascade` - deleting a project automatically cleans up its links and tag connections
- **Key constraints**:
- `Project.slug`: Unique
- `Tag.name`: Unique (tag names are globally unique)
- `Tag.slug`: Unique
- `ExternalLink`: `@@unique([projectId, url])` (each project can't have duplicate URLs)
- **Indexes**: `idx_project_status_createdAt`, `idx_project_slug`, `idx_tag_slug`, `idx_link_projectId`, `idx_link_type`, `idx_link_type_url` (composite for efficient URL-based deduplication)
#### Neon Database Setup
- **Dashboard**: https://console.neon.tech
- **Connection String Format**: `postgres://[user]:[password]@[host]/[database]?sslmode=require`
- **Vercel Integration**: Set `DATABASE_URL` environment variable in Vercel Dashboard (do NOT use `vercel.json` env references)
- **Free Tier**: 0.5GB storage, 300 hours compute/month
- **Run Migrations**: After deployment, run `pnpm prisma db push` or use Neon's SQL Editor to create tables
### Webhook Deduplication Strategy
The webhook at `src/app/api/webhook/projects/route.ts` implements a **multi-level deduplication** strategy to prevent duplicate projects:
1. **GitHub URL exact match** (highest priority) - via `ExternalLink` table using `idx_link_type_url` index
2. **Website URL exact match** - via `ExternalLink` table using `idx_link_type_url` index
3. **slug match** (fallback) - via `Project.slug` field
When updating an existing project, the webhook:
- Updates all project fields (name, description, content, status, source)
- Replaces all tags (deletes old `ProjectTag` connections via `ProjectTag` table, creates new ones)
- Replaces all links (deletes old `ExternalLink` entries, creates new ones)
**Tag handling special case**: Due to `Tag.name` unique constraint, tag upsert follows:
1. First try to find existing tag by name
2. If not found, try upsert by slug
3. If slug conflicts, use the existing tag with that slug
### Data Fetching (Server-Side)
- **Location**: `src/hooks/useProjects.ts` (server functions, not React hooks)
- **Functions**: `getProjects()`, `getProjectBySlug()`, `getAllTags()`, `getTagsWithProjectCounts()`
- **Usage**: Directly called in Server Components and route handlers
- **Query transformation**: `getProjects()` and `getProjectBySlug()` flatten the `ProjectTag` junction table structure to return tags directly
- **ISR**: Project detail pages use `export const revalidate = 300` (5 minutes) at `src/app/[locale]/projects/[id]/page.tsx`
### Validation (Zod)
- **Schemas**: `src/lib/validations.ts` defines all Zod schemas
- `ProjectInputSchema`: Validates incoming project data (1-10 tags, 1-10 links required)
- `WebhookPayloadSchema`: Validates webhook requests with API key (1-100 projects per request)
- `ProjectQuerySchema`: Validates query parameters (search, tags, status, page, limit)
### Styling (Tailwind CSS)
- **Neo-brutalism design**: Sharp corners (0px radius), bold borders (4px shadows), hard edges
- **Theme colors**:
- Primary: Gold (#FFD700)
- Secondary: Orange (#ff6f00)
- Background light: #F5F2EB, dark: #121212
- Surface light: #FFFFFF, dark: #1E1E1E
- **Typography**: Space Mono (headings), Inter (body)
- **Dark mode**: Class-based with `dark:` prefix
- **Config**: `tailwind.config.ts` extends theme with custom colors, shadows, and animations
### Content Rendering
- **Markdown**: Project content fields support Markdown via `react-markdown`
- **Plugins**: `rehype-raw`, `rehype-sanitize`, `rehype-shiki`, `remark-gfm`
- **Usage**: `ProjectDetail` component renders `content`/`contentEn` as Markdown
### UI Components
- **Radix UI primitives**: `@radix-ui/react-slot`, `@radix-ui/react-navigation-menu`, `@radix-ui/react-dropdown-menu`, `@radix-ui/react-separator`
- **Lucide React icons**: Used throughout the app (package imports optimized via `experimental.optimizePackageImports`)
- **Custom components**: `src/components/` organized by domain
- `layout/`: Header, Footer, AnnouncementBar
- `locale/`: LocaleSwitcher
- `project/`: ProjectCard, ProjectList, ProjectDetail, ProjectSidebar, RelatedProjects, TagCloud, ExternalLinkCard, ShareButtons, MarkdownContent, GitHubBadges, GitHubTextStatsCard
- `search/`: SearchBar
- `ui/`: Base UI components (buttons, cards, etc.)
### Next.js Configuration
- **next.config.js**:
- `next-intl` plugin wrapper for i18n
- Image domains: localhost, *.anthropic.com, img.shields.io
- Lucide-react package import optimization
- **tsconfig.json**: ES2017 target, strict mode enabled, noUncheckedIndexedAccess enabled
- **Testing**: Vitest for unit tests, Playwright for E2E tests (configured but not extensively used yet)
### Project Discovery System
项目发现系统是自动化探索和收录 AI 项目的核心功能,采用**双 Agent 协作架构**实现上下文隔离:
#### 架构组件
1. **自定义 Agents** (`.claude/agents/`):
- `content-explorer-agent`: 项目内容探索专家,批量探索项目并生成结构化数据
- 使用 `agent-browser` 子任务并行探索 GitHub 项目
- 应用严格的内容质量标准(客观描述、避免营销术语、不写入动态数据)
- 生成符合 `ProjectInputSchema` 的 JSON 数据
- `api-submitter-agent`: API 提交专家,处理探索结果的提交和状态更新
- 批量标记任务为 IN_PROGRESS
- 提交探索数据到完成 API
- 自动重试失败的提交(指数退避,最多3次)
2. **Claude Commands** (`.claude/commands/`):
- `/discover-projects`: 主命令,协调探索和提交流程
- 参数解析(任务数量、批次大小)
- 分批处理(默认每批3个任务)
- Agent 调度和进度显示
- 结果汇总和错误报告
3. **API Endpoints** (`src/app/api/discovery/`):
- `POST /api/discovery/tasks`: 创建新的探索任务(支持批量)
- `GET /api/discovery/tasks`: 获取待处理任务列表(支持 status/limit/offset 过滤)
- `PATCH /api/discovery/tasks/{id}`: 更新任务状态
- `POST /api/discovery/tasks/{id}/complete`: 完成任务并提交项目数据
- `GET /api/webhook/check-duplicates`: 检查项目是否已存在(URL 去重)
4. **Database Model**:
- `ProjectDiscoveryTask`: 任务追踪表
- 状态: PENDING → IN_PROGRESS → COMPLETED/FAILED
- 原始数据: `sourceUrl`, `sourceType`
- 探索结果: `explorationData` (JSON), `explorationSummary`
- 错误处理: `errorMessage`, `retryCount`, `lastRetryAt`
- 索引: `idx_task_status_created`, `idx_task_source_url`, `idx_task_project_id`
#### 数据流转
```
用户输入 URL → 创建 PENDING 任务 → /discover-projects 命令
分批获取任务(每批3个)
Content Explorer Agent (并行探索) → 探索结果 JSON
API Submitter Agent (提交到生产环境 API)
更新任务状态 → COMPLETED/FAILED
```
#### 质量标准
- **数据模板**: `.claude/schemas/project-content-template.md`
- **描述要求**: 清晰说明功能、突出价值、避免营销术语、10-500字
- **内容要求**: 从 README 提取并重新组织、不机械翻译、符合中文表达习惯
- **链接要求**: 必须包含 GITHUB 链接、所有链接可访问
- **标签要求**: 1-10 个标签、技术/应用/状态分类
- **动态数据处理**: Star/Fork 数量等动态数据不写入内容,使用 GitHub Badge 显示
#### 环境变量
- `WEBHOOK_API_KEY`: 生产环境 API 密钥(必需,用于认证)
#### 使用示例
```bash
# 处理默认10个任务(每批3个)
/discover-projects
# 处理指定数量的任务
/discover-projects 5
# 自定义批次大小
/discover-projects 9 --batch=2
# 处理所有待处理任务
/discover-projects all --batch=5
```
### Keyword Cloud System (季度 AI 热点词云)
**功能**: 自动化采集 Google Trends 数据,展示季度 AI 热点词汇词云。
**数据流**: n8n 工作流 → AI 清洗 → 规则匹配 → PostgreSQL → Next.js 前端
#### 数据库表
- `Quarter`: 季度元数据(quarter, title, titleEn, subtitle, subtitleEn, displayOrder, isActive
- `Keyword`: 关键词数据(word, trendScore, description, visualConfig
- `VisualStyleRule`: 视觉样式规则配置(name, minScore, maxScore, color, size, border, rotation
- `KeywordCloudErrorLog`: 错误日志(quarter, keyword, errorType, errorMessage
#### API 端点
- `GET /api/keyword-cloud/quarters`: 获取季度列表(支持 `isActive` 过滤)
- `GET /api/keyword-cloud/keywords/[quarter]`: 获取指定季度的关键词
- `GET /api/keyword-cloud/rules`: 获取视觉样式规则配置
- `POST /api/keyword-cloud/keywords`: 批量写入关键词(n8n 使用,需 API Key 认证)
- `GET /api/keyword-cloud/health`: 健康检查端点(返回系统统计信息)
#### 前端路由
- `/[locale]/keyword-cloud`: 词云展示页面
#### 前端组件
- `CloudWord`: 单个词汇组件(支持颜色、大小、边框、旋转、悬停弹出框)
- `QuarterNavigator`: 季度导航组件(前后切换)
- `ProgressIndicator`: 进度条组件(显示季度进度)
- `KeywordCloud`: 主容器组件(集成所有子组件)
#### 数据访问层
- **Location**: `src/hooks/useKeywordCloud.ts` (服务器端函数)
- **Functions**:
- `getAllQuarters()`: 获取所有季度列表
- `getQuarterByQuarter()`: 获取单个季度详情(含关键词计数)
- `getKeywordsByQuarter()`: 获取指定季度的所有关键词
- `getVisualStyleRules()`: 获取视觉样式规则
- `upsertQuarter()`: 创建或更新季度
- `createKeywords()`: 批量创建关键词
- `logKeywordCloudError()`: 记录错误日志
#### 客户端 Hook
- **Location**: `src/hooks/useKeywordCloudClient.ts`
- **Function**: `useKeywordCloud(quarter)` - 响应式获取季度关键词数据
#### n8n 工作流
- **配置文件**: `n8n-workflows/keyword-cloud-workflow.json`
- **文档**: `n8n-workflows/README.md`
- **流程**:
1. Schedule Trigger: 每季度末最后一天的 23:00 自动触发
2. Calculate Quarter: 计算当前季度标识和时间范围
3. Google Trends: 采集热门搜索词
4. Extract Keywords: 提取关键词和热度分数
5. Get Visual Rules: 获取视觉样式规则
6. Match Visual Rules: 为关键词匹配视觉样式
7. Send to API: 写入数据库
#### 初始化数据
```bash
# 运行种子数据脚本(创建视觉规则和示例数据)
pnpm tsx scripts/seed-keyword-cloud.ts
```
#### 测试 API
```bash
# 运行 API 测试脚本
set -a && source .env.local && set +a && npx tsx scripts/test-keyword-api.ts
```
#### 环境变量
- `WEBHOOK_API_KEY`: n8n 工作流使用的 API 密钥(必需)
- n8n 环境变量(在 n8n 中设置):
- `API_URL`: API 端点 URL(如 `http://localhost:3000`
- `API_KEY`: 与 `WEBHOOK_API_KEY` 相同
## MCP Servers Usage (按需使用)
1. **context7**: 不确定 API 用法时查阅最新文档
2. **chrome-devtools-mcp**: 查看页面效果、调试 UI 修复 BUG
3. **web-search-prime**: 默认联网搜索工具
4. **vision-mcp-server**: 图片/视频理解
## Git Commits
Git 提交信息遵循约定式提交格式(详见上方 Code Quality & Standards → Git Commit Conventions)。
## Development Workflow
- Before viewing the page, check if there's already a project running at localhost:3000. If yes, access it directly; if no, then run `pnpm dev`
- The dev server runs with hot-reload enabled for fast iteration
- The middleware handles locale detection and routing automatically - no manual locale configuration needed
- When adding new translations, update both `src/messages/zh.json` and `src/messages/en.json`
- Database changes require running `pnpm prisma migrate dev` to update the schema
- **Always verify API responses** with `WEBHOOK_API_KEY` when testing webhook or discovery endpoints
- **Use `pnpm prisma studio`** to inspect database state during development
## Common Development Patterns
### Adding a New API Endpoint
1. Create route file in `src/app/api/` (e.g., `src/app/api/your-endpoint/route.ts`)
2. Import validation schemas from `@/lib/validations`
3. Use `crypto.timingSafeEqual()` for API key authentication (see webhook route:36-43)
4. Implement partial success mode for batch operations (see webhook route:55-67)
5. Return structured errors with `NextResponse.json()`
### Adding New Database Fields
1. Update `prisma/schema.prisma` with new fields
2. Run `pnpm prisma migrate dev --name your_migration_name`
3. Update Zod schemas in `src/lib/validations.ts`
4. Update TypeScript types in `src/hooks/useProjects.ts` if needed
5. Regenerate Prisma client: `pnpm prisma generate`
### Creating Custom Agents
1. Create agent file in `.claude/agents/your-agent.md`
2. Define agent role, capabilities, and task instructions
3. Reference existing agents (`content-explorer-agent`, `api-submitter-agent`) as templates
4. Test via corresponding Claude Command in `.claude/commands/`
### Working with Multilingual Content
- All user-facing content should have both Chinese (`name`, `description`) and English (`nameEn`, `descriptionEn`) versions
- Use `src/messages/zh.json` and `src/messages/en.json` for UI translations
- For project data, prefer Chinese as primary language with English as optional
- When creating content, avoid mechanical translation - write naturally for each locale
## Code Quality & Standards
### TypeScript Configuration
- **Strict mode enabled** with additional safety flags: `noUncheckedIndexedAccess`, `noImplicitReturns`, `noFallthroughCasesInSwitch`
- Path alias: `@/*` maps to `./src/*`
- Target: ES2017 for modern browser support
### Validation & Security
- **API Authentication**: Webhook uses timing-safe comparison (`crypto.timingSafeEqual`) to prevent timing attacks
- **Input Validation**: All API inputs use Zod schemas with detailed error messages
- **SQL Injection Prevention**: Prisma ORM with parameterized queries
- **Data Sanitization**: Markdown content sanitized with `rehype-sanitize` plugin
### Error Handling Patterns
- **Webhook**: Partial success mode - continues processing remaining projects even if individual projects fail
- **Database**: Unique constraints use try-catch with fallback logic (e.g., tag slug conflicts in webhook)
- **Console**: Use `console.warn()` for operational logs, `console.error()` for errors
### Git Commit Conventions
- **Format**: `<type>: <description>` (type in lowercase Chinese: feat/fix/refactor/chore)
- **Types**: `feat` (新功能), `fix` (修复), `refactor` (重构), `chore` (杂项)
- **Examples**:
- `feat: 新增项目发现任务系统`
- `fix: 修复 ESLint 警告`
- `refactor: 重构项目内容标准实现职责分离`
## Testing Strategy
### Unit Tests (Vitest)
- Location: Test files co-located with source code (e.g., `*.test.ts`)
- Run: `pnpm test` for all tests, `pnpm test <pattern>` for specific tests
- Configuration: Vitest with `@testing-library/jest-dom` matchers
### E2E Tests (Playwright)
- Location: `tests/e2e/` or co-located with features
- Run: `pnpm test:e2e` to execute all E2E tests
- Usage: Focus on critical user journeys (project browsing, search, locale switching)
## Performance Considerations
### Database Optimization
- **Index Strategy**: Composite indexes on frequently queried fields (status+createdAt, type+url)
- **N+1 Prevention**: Batch queries for tags (see webhook route:94-98)
- **Connection Pooling**: Prisma client singleton pattern (`src/lib/prisma.ts`)
### Frontend Performance
- **ISR**: Project detail pages revalidated every 5 minutes (`revalidate = 300`)
- **Package Optimization**: Lucide-react imports optimized via `experimental.optimizePackageImports`
- **Image Domains**: Pre-configured for localhost, *.anthropic.com, img.shields.io
### API Rate Limiting
- Webhook: Max 100 projects per request
- Discovery tasks: Max 50 tasks per batch creation
- All queries: Max 100 items per page (enforced via Zod schemas)
## Troubleshooting
### Common Issues
**Database Connection Errors**
- Verify `DATABASE_URL` is set in `.env.local`
- Check Neon dashboard for database status
- Run `pnpm prisma db push` to sync schema if needed
**Webhook Authentication Failures**
- Ensure `WEBHOOK_API_KEY` is set and matches (32+ characters)
- Check that API key is sent in request body
- Verify timing-safe comparison is used (never log raw API keys)
**Missing Translations**
- All new UI text must be added to both `src/messages/zh.json` and `src/messages/en.json`
- Missing keys will display as `missing_key_name` in the UI
- Test both locales (switch via URL path `/zh/` or `/en/`)
**Build Errors After Schema Changes**
- Run `pnpm prisma generate` to regenerate Prisma client
- Restart dev server after schema changes
- Check for TypeScript errors in generated types
**Discovery Task Failures**
- Check `src/app/api/discovery/lib/discovery-service.ts:16-80` for deduplication logic
- Verify `WEBHOOK_API_KEY` is set for api-submitter-agent
- Use `pnpm prisma studio` to inspect task status and error messages
- Check browser console for agent-browser errors (requires chrome-devtools-mcp)
### Debugging Tips
1. **Enable Prisma Query Logging**:
```typescript
// In src/lib/prisma.ts
export const prisma = new PrismaClient({
log: ['query', 'error', 'warn'],
})
```
2. **Check Database State**:
```bash
pnpm prisma studio
# Opens at http://localhost:5555
```
3. **Test API Endpoints**:
```bash
# Create discovery task
curl -X POST http://localhost:3000/api/discovery/tasks \
-H "Content-Type: application/json" \
-d '{"apiKey":"YOUR_KEY","tasks":[{"sourceUrl":"https://github.com/user/repo"}]}'
```
4. **Validate Request Payloads**:
- All schemas are in `src/lib/validations.ts`
- Check schema errors in API response `details` field
- Ensure all required fields are present
### Environment Variables Checklist
For local development, ensure these are set in `.env.local`:
```bash
# Database (Neon PostgreSQL)
DATABASE_URL="postgres://[user]:[password]@[host]/[database]?sslmode=require"
# Webhook API Key (32+ characters)
WEBHOOK_API_KEY="your-secret-api-key-min-32-chars"
```
For production deployment (Vercel):
- Set `DATABASE_URL` in Vercel Dashboard (Environment Variables)
- Set `WEBHOOK_API_KEY` in Vercel Dashboard
- Run `pnpm prisma db push` after first deployment to create tables
- Do NOT use `vercel.json` for environment variables