docs: 生成层次化 AGENTS.md 文档系统
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
# PROJECT KNOWLEDGE BASE
|
||||
|
||||
**Generated:** 2026-02-01
|
||||
**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.
|
||||
|
||||
## STRUCTURE
|
||||
|
||||
```
|
||||
agent_park/
|
||||
├── src/
|
||||
│ ├── app/ # Next.js App Router (locale-prefixed routes)
|
||||
│ │ ├── [locale]/ # Internationalized routes (zh/en)
|
||||
│ │ │ ├── projects/ # Project listing and details
|
||||
│ │ │ ├── keyword-cloud/ # Quarterly AI trends
|
||||
│ │ │ └── layout.tsx # Header/footer/Announcement
|
||||
│ │ ├── api/ # API routes (no locale prefix)
|
||||
│ │ │ ├── webhook/ # Project ingestion
|
||||
│ │ │ ├── discovery/ # Automated exploration tasks
|
||||
│ │ │ ├── search/ # AI-powered search
|
||||
│ │ │ └── keyword-cloud/ # Keywords API
|
||||
│ │ ├── components/ # React components (organized by domain)
|
||||
│ │ ├── lib/ # Validation, utilities, Prisma client
|
||||
│ │ ├── hooks/ # Server-side data fetching
|
||||
│ │ └── i18n/ # next-intl configuration
|
||||
│ └── layout.tsx # Root layout (locale default: zh)
|
||||
├── prisma/
|
||||
│ └── schema.prisma # Database models (multilingual support)
|
||||
├── .claude/
|
||||
│ ├── agents/ # Custom Claude agents
|
||||
│ └── commands/ # Claude commands
|
||||
├── scripts/ # Seed/test scripts
|
||||
├── public/ # Static assets
|
||||
└── CLAUDE.md # This file (existing)
|
||||
```
|
||||
|
||||
## WHERE TO LOOK
|
||||
|
||||
| Task | Location | Notes |
|
||||
| ------------------- | ------------------------ | ------------------------------------------- |
|
||||
| Add new page | `src/app/[locale]/` | Follow locale routing pattern |
|
||||
| Create API endpoint | `src/app/api/` | Use `crypto.timingSafeEqual()` for auth |
|
||||
| Add component | `src/components/` | Neo-brutalism: 0px radius, bold borders |
|
||||
| Database migration | `prisma/schema.prisma` | Run `pnpm prisma migrate dev` after changes |
|
||||
| Add validation | `src/lib/validations.ts` | Follow existing Zod schema patterns |
|
||||
| Fetch data | `src/hooks/` | Server functions, NOT React hooks |
|
||||
| Webhook | `src/app/api/webhook/` | Multi-level deduplication strategy |
|
||||
| Discovery task | `src/app/api/discovery/` | Task management API |
|
||||
| i18n messages | `src/messages/` | Update BOTH `zh.json` AND `en.json` |
|
||||
|
||||
## CODE MAP
|
||||
|
||||
```
|
||||
Main Entry Points:
|
||||
├── src/app/[locale]/layout.tsx → Root layout (header/footer)
|
||||
├── src/app/[locale]/page.tsx → Home page (ISR 5min)
|
||||
├── src/app/layout.tsx → Root layout (fonts, locale)
|
||||
└── src/middleware.ts → Locale detection (next-intl)
|
||||
|
||||
Data Layer:
|
||||
├── src/hooks/useProjects.ts → Projects/tags/search
|
||||
├── src/hooks/useKeywordCloud.ts → Keywords/quarters/rules
|
||||
└── src/lib/prisma.ts → Prisma client singleton
|
||||
|
||||
API Routes:
|
||||
├── src/app/api/webhook/projects/route.ts → Project ingestion
|
||||
├── src/app/api/discovery/tasks/route.ts → Task CRUD
|
||||
├── src/app/api/search/ai/route.ts → AI search
|
||||
└── src/app/api/keyword-cloud/[...]/route.ts → Keywords API
|
||||
|
||||
Complex Components:
|
||||
├── src/components/project/MarkdownContent.tsx (269 lines) → Markdown renderer
|
||||
├── src/app/api/discovery/lib/discovery-service.ts → Deduplication logic
|
||||
└── src/app/api/webhook/projects/route.ts → Webhook handler
|
||||
```
|
||||
|
||||
## CONVENTIONS
|
||||
|
||||
### Multilingual Architecture
|
||||
|
||||
- **Default locale**: Chinese (`zh`), not English
|
||||
- **Route pattern**: `/{locale}/path` (locale prefix ALWAYS required)
|
||||
- **Field naming**: Dual-language pairs (`name`/`nameEn`, `description`/`descriptionEn`)
|
||||
- **Content selection**: `locale === 'en' && fieldEn ? fieldEn : field`
|
||||
- **Translation files**: Update BOTH `src/messages/zh.json` AND `src/messages/en.json`
|
||||
|
||||
### Type Safety
|
||||
|
||||
- **Strict mode**: Enabled with `noUncheckedIndexedAccess`, `noImplicitReturns`, `noFallthroughCasesInSwitch`
|
||||
- **Path aliases**: `@/*` maps to `./src/*`
|
||||
- **Validation**: All API inputs via Zod schemas in `src/lib/validations.ts`
|
||||
|
||||
### Database Patterns
|
||||
|
||||
- **Multi-level deduplication**: GitHub URL → Website URL → slug match (highest → lowest priority)
|
||||
- **Cascade deletion**: `ExternalLink` and `ProjectTag` auto-delete on project delete
|
||||
- **Composite indexes**: Optimized for frequent queries (`status+createdAt`, `type+url`)
|
||||
- **Constraints**: `Project.slug` unique, `Tag.name` unique, `ExternalLink(projectId, url)` unique
|
||||
|
||||
### API Authentication
|
||||
|
||||
- **Method**: `crypto.timingSafeEqual()` for timing-safe comparison (prevents timing attacks)
|
||||
- **Key location**: Request body (NOT headers)
|
||||
- **Validation**: WEBHOOK_API_KEY (32+ chars)
|
||||
|
||||
### Design System (Neo-Brutalism)
|
||||
|
||||
- **Corners**: 0px radius (sharp)
|
||||
- **Shadows**: 4px solid borders (`shadow-neo` class)
|
||||
- **Colors**: Primary gold (#FFD700), secondary orange (#ff6f00)
|
||||
- **Typography**: Space Mono (headings), Inter (body)
|
||||
- **Dark mode**: Class-based with `dark:` prefix
|
||||
|
||||
### Git Commits
|
||||
|
||||
- **Format**: `<type>: <description>` (Chinese lowercase types)
|
||||
- **Types**: `feat` (新功能), `fix` (修复), `refactor` (重构), `chore` (杂项)
|
||||
- **Examples**:
|
||||
- `feat: 新增项目发现任务系统`
|
||||
- `fix: 修复 ESLint 错误`
|
||||
|
||||
## ANTI-PATTERNS (THIS PROJECT)
|
||||
|
||||
### Environment Variables
|
||||
|
||||
- **NEVER** use `vercel.json` for env vars (use Vercel Dashboard)
|
||||
- **NEVER** commit `.env.local` files or environment variables
|
||||
- **ALWAYS** verify API responses with `WEBHOOK_API_KEY` when testing endpoints
|
||||
|
||||
### Database Operations
|
||||
|
||||
- **NEVER** modify schema without running migrations
|
||||
- **ALWAYS** run `pnpm prisma migrate dev --name <migration_name>` after schema changes
|
||||
- **ALWAYS** run `pnpm prisma generate` after migrations
|
||||
|
||||
### Development Workflow
|
||||
|
||||
- **NEVER** skip pre-commit hooks (no `--no-verify`, `--no-gpg-sign` flags)
|
||||
- **NEVER** commit unless explicitly requested by orchestrator
|
||||
- **ALWAYS** run `pnpm build` before committing
|
||||
- **MUST** use chrome-devtools-mcp to verify frontend changes
|
||||
|
||||
### Content Standards
|
||||
|
||||
- **NEVER** include dynamic data (star/fork counts) in project content
|
||||
- **ALWAYS** use GitHub Badge for dynamic stats
|
||||
- **NEVER** use mechanical translation - write naturally for each locale
|
||||
- **ALWAYS** avoid marketing terminology in descriptions
|
||||
|
||||
### Security
|
||||
|
||||
- **NEVER** use string comparison for API keys (timing attacks)
|
||||
- **ALWAYS** use `crypto.timingSafeEqual()` for authentication
|
||||
- **ALWAYS** validate inputs with Zod schemas
|
||||
- **NEVER** log raw API keys or sensitive data
|
||||
|
||||
## UNIQUE STYLES
|
||||
|
||||
### Project Discovery System
|
||||
|
||||
- **Architecture**: Dual-agent system (`content-explorer-agent` + `api-submitter-agent`)
|
||||
- **Workflow**: URL input → PENDING tasks → batch processing → COMPLETED/FAILED
|
||||
- **Deduplication**: Multi-level strategy (GitHub → Website → slug)
|
||||
- **Retry logic**: Exponential backoff, max 3 attempts
|
||||
- **Environment**: `WEBHOOK_API_KEY` required for submitter agent
|
||||
- See: `src/app/AGENTS.md` for app-specific patterns
|
||||
|
||||
### Keyword Cloud System
|
||||
|
||||
- **Workflow**: n8n automation → API → PostgreSQL → Next.js
|
||||
- **Data**: Quarterly snapshots with visual style rules
|
||||
- **API**: Rate-limited, requires API key
|
||||
- **Error logging**: `KeywordCloudErrorLog` table
|
||||
- See: `src/app/AGENTS.md` for app-specific patterns
|
||||
|
||||
### Component System
|
||||
|
||||
- **Design**: Neo-brutalism with 0px corners, 4px solid borders, gold/orange theme
|
||||
- **Organization**: layout/locale/project/search/ui (4 domains), project/ (11 files, highest)
|
||||
- **Largest component**: `MarkdownContent.tsx` (269 lines) with complex react-markdown overrides
|
||||
- **See**: `src/components/AGENTS.md` for component-specific patterns
|
||||
|
||||
### Data Access Layer
|
||||
|
||||
- **Validation**: Centralized Zod schemas in `src/lib/validations.ts`
|
||||
- **Utilities**: Class merging (`cn()`), slug generation, Prisma client singleton
|
||||
- **GitHub integration**: Badge-based approach, cached API stats (5min)
|
||||
- **See**: `src/lib/AGENTS.md` for library patterns
|
||||
|
||||
### Server-Side Hooks
|
||||
|
||||
- **Purpose**: Server functions for data fetching, NOT React hooks
|
||||
- **Query optimization**: N+1 prevention, selective loading, index utilization
|
||||
- **ISR strategy**: 5-minute revalidation on project details
|
||||
- **See**: `src/hooks/AGENTS.md` for data fetching patterns
|
||||
|
||||
## COMMANDS
|
||||
|
||||
```bash
|
||||
pnpm dev # Start dev server (Next.js 15)
|
||||
pnpm build # Production build
|
||||
pnpm start # Start production server
|
||||
pnpm lint # ESLint check
|
||||
pnpm test # Vitest unit tests
|
||||
pnpm test:e2e # Playwright E2E tests
|
||||
pnpm prisma migrate dev # Run migrations
|
||||
pnpm prisma db seed # Seed database
|
||||
pnpm prisma studio # Database inspector
|
||||
```
|
||||
|
||||
## NOTES
|
||||
|
||||
### Project Discovery Gotchas
|
||||
|
||||
- Tag upsert follows: 1) Find by name, 2) Try upsert by slug, 3) Use existing if slug conflicts
|
||||
- Webhook updates ALL project fields, replaces ALL tags/links (no partial updates)
|
||||
- Deduplication logic in `src/app/api/discovery/lib/discovery-service.ts:16-80`
|
||||
|
||||
### i18n Gotchas
|
||||
|
||||
- Missing translation keys display as `missing_key_name` in UI
|
||||
- All new UI text requires BOTH `zh.json` AND `en.json` updates
|
||||
- Test both locales: `/{zh}/path` and `/{en}/path`
|
||||
|
||||
### Database Gotchas
|
||||
|
||||
- `Project.slug` globally unique - use existing project if slug conflicts
|
||||
- `Tag.name` globally unique - upsert handles conflicts via slug fallback
|
||||
- Run `pnpm prisma studio` to inspect state during development
|
||||
|
||||
### Performance Considerations
|
||||
|
||||
- **ISR**: Project detail pages revalidate every 5 minutes (`revalidate = 300`)
|
||||
- **Indexes**: Composite on `(status, createdAt)`, `(type, url)` for optimized queries
|
||||
- **N+1 prevention**: Batch tag queries in webhook (`useProjects.ts`)
|
||||
|
||||
### Missing CI/CD
|
||||
|
||||
- No GitHub Actions workflows (rely on Vercel deployment)
|
||||
- No automated testing in CI pipeline
|
||||
- Test frameworks configured (Vitest, Playwright) but not extensively used
|
||||
|
||||
### LSP Errors
|
||||
|
||||
- Missing Prisma models in `src/hooks/useKeywordCloud.ts` and `scripts/seed-keyword-cloud.ts`:
|
||||
- Run `pnpm prisma migrate dev` to generate keyword cloud tables
|
||||
- Models: `Quarter`, `Keyword`, `VisualStyleRule`, `keywordCloudErrorLog`
|
||||
|
||||
### Subdirectories
|
||||
|
||||
- **src/app/**: App Router architecture, locale routing, API structure (see `src/app/AGENTS.md`)
|
||||
- **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`)
|
||||
@@ -0,0 +1,46 @@
|
||||
# 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)
|
||||
- `globals.css` - Tailwind + neo-brutalism styles
|
||||
- `layout.tsx` - Root layout
|
||||
|
||||
## WHERE TO LOOK
|
||||
|
||||
- **Locale routing**: `src/middleware.ts`, `src/app/[locale]/layout.tsx`
|
||||
- **API patterns**: `src/app/api/webhook/projects/route.ts`
|
||||
- **ISR configuration**: `src/app/[locale]/projects/[id]/page.tsx:93`
|
||||
- **Discovery system**: `src/app/api/discovery/tasks/route.ts`
|
||||
|
||||
## CONVENTIONS
|
||||
|
||||
- **Middleware**: `createMiddleware({ locales: ['zh', 'en'], defaultLocale='zh', localePrefix='always' })`
|
||||
- **Route params**: Always `params: Promise<{...}>`, await before use
|
||||
- **Locale setup**: `setRequestLocale(locale)` in layouts/pages
|
||||
- **Translations**: `getTranslations('namespace')` for server-side
|
||||
- **API auth**: `crypto.timingSafeEqual()` for timing-safe API key validation
|
||||
- **Webhook**: Partial success mode - continue processing if individual items fail
|
||||
- **Deduplication**: Multi-level (GitHub URL → Website URL → slug) via `discovery-service`
|
||||
- **ISR**: Export `revalidate = N` constant in page files
|
||||
- **Parallel queries**: `Promise.all()` for independent data fetching
|
||||
- **N+1 prevention**: Batch queries with `findMany({ where: { field: { in: [...] } } })`
|
||||
- **Content selection**: `locale === 'en' && fieldEn ? fieldEn : field` pattern
|
||||
|
||||
## ANTI-PATTERNS
|
||||
|
||||
- NEVER bypass locale routing (API routes excluded)
|
||||
- NEVER use `crypto.compare()` or string comparison for API keys (timing attacks)
|
||||
- NEVER skip Zod validation in API routes
|
||||
- NEVER embed API keys in error responses (log only)
|
||||
- NEVER process webhook without partial success mode
|
||||
- NEVER run queries in loops (N+1 problem)
|
||||
- NEVER use client-side translations in server components
|
||||
- NEVER skip `setRequestLocale()` in locale routes
|
||||
- NEVER omit ISR for dynamic content (5+ minute revalidation)
|
||||
- NEVER return raw database errors to clients
|
||||
@@ -0,0 +1,60 @@
|
||||
# Component System Architecture
|
||||
|
||||
## Neo-Brutalism Design Principles
|
||||
|
||||
**Visual Identity:**
|
||||
|
||||
- Sharp corners (0px radius) - no rounded edges
|
||||
- Bold borders (4px solid shadows) for depth
|
||||
- High contrast colors with hard edges
|
||||
- Gold (#FFD700) primary, Orange (#ff6f00) secondary
|
||||
- Space Mono headings, Inter body text
|
||||
|
||||
**Component Styling:**
|
||||
|
||||
```tsx
|
||||
// Base button pattern - no border-radius, hard shadows
|
||||
className="border-4 border-black shadow-[4px_4px_0px_0px_rgba(0,0,0,1)]
|
||||
hover:translate-x-1 hover:translate-y-1 hover:shadow-[2px_2px_0px_0px_rgba(0,0,0,1)]"
|
||||
```
|
||||
|
||||
## Component Organization
|
||||
|
||||
```
|
||||
src/components/
|
||||
├── layout/ # Layout primitives (Header, Footer, AnnouncementBar)
|
||||
├── locale/ # I18n utilities (LocaleSwitcher)
|
||||
├── project/ # Project-specific components (ProjectCard, ProjectDetail)
|
||||
├── search/ # Search functionality (SearchBar)
|
||||
└── ui/ # Base UI components (Button, Card, Badge)
|
||||
```
|
||||
|
||||
## Component Patterns
|
||||
|
||||
### Composition Pattern
|
||||
|
||||
- Build complex components from small reusable primitives
|
||||
- Example: `ProjectCard` = `Card` + `Badge` + `ExternalLink`
|
||||
|
||||
### Server Components First
|
||||
|
||||
- Default to Server Components for data fetching
|
||||
- Use Client Components (`"use client"`) only for interactivity
|
||||
- Pass server data via props to client components
|
||||
|
||||
### Responsive Design
|
||||
|
||||
- Mobile-first Tailwind classes: `grid-cols-1 md:grid-cols-2 lg:grid-cols-3`
|
||||
- Breakpoints: md (768px), lg (1024px)
|
||||
|
||||
### Accessibility
|
||||
|
||||
- Semantic HTML elements
|
||||
- Keyboard navigation support
|
||||
- ARIA labels where needed
|
||||
|
||||
## State Management
|
||||
|
||||
- Server state: Prisma queries in Server Components
|
||||
- Client state: React hooks (useState, useEffect) for interactivity
|
||||
- Global state: Context providers for locale, theme
|
||||
@@ -0,0 +1,49 @@
|
||||
# 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
|
||||
|
||||
- **Server Functions Only**: No React hooks, no client-side state
|
||||
- **Direct Prisma Queries**: ORM queries with optimization patterns
|
||||
- **ISR Support**: Used by Next.js App Router for incremental static revalidation
|
||||
|
||||
## Key Functions
|
||||
|
||||
### Project Data (`useProjects.ts`)
|
||||
|
||||
- `getProjects()`: List projects with tags, pagination, filtering (search/tags/status)
|
||||
- Flattens `ProjectTag` junction table to return tags directly
|
||||
- Optimized for list queries with selective field loading
|
||||
- `getProjectBySlug(slug)`: Get single project by slug
|
||||
- Used by ISR pages with 5-min revalidation
|
||||
- Includes all tags and external links
|
||||
- `getAllTags()`: All tags with project counts
|
||||
- `getTagsWithProjectCounts()`: Tags sorted by popularity (count DESC)
|
||||
|
||||
### Keyword Cloud (`useKeywordCloud.ts`)
|
||||
|
||||
- `getAllQuarters()`: List all quarters with metadata
|
||||
- `getQuarterByQuarter(quarter)`: Single quarter with keyword count
|
||||
- `getKeywordsByQuarter(quarter)`: All keywords for a quarter
|
||||
- `getVisualStyleRules()`: Visual style configuration for word cloud
|
||||
|
||||
## Query Optimization Patterns
|
||||
|
||||
**N+1 Prevention**: Batch queries for related data (tags, links)
|
||||
**Selective Loading**: Only fetch required fields via Prisma `select`
|
||||
**Index Utilization**: Leverages database indexes (status+createdAt, slug, etc.)
|
||||
**Pagination**: Limit/offset to prevent large result sets
|
||||
|
||||
## ISR Strategy
|
||||
|
||||
- **Revalidation**: 5-minute revalidate on project detail pages
|
||||
- **Stale Data Acceptable**: Project listings tolerate slight staleness
|
||||
- **Cache Busting**: Use `revalidatePath()` when data changes via webhook
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Always import via `@/hooks/use*` (not relative paths)
|
||||
- Return plain objects/arrays, never Prisma model instances
|
||||
- Handle errors at route level, not in these functions
|
||||
- Add new functions to existing files or create new `use*.ts` files
|
||||
@@ -0,0 +1,66 @@
|
||||
# src/lib/ - Core Utilities
|
||||
|
||||
## Overview
|
||||
|
||||
Shared utilities and infrastructure layers used across the application.
|
||||
|
||||
## Key Files
|
||||
|
||||
### Validation Layer (`validations.ts`)
|
||||
|
||||
**Purpose**: Input validation and type safety using Zod schemas
|
||||
|
||||
- `ProjectInputSchema`: Project data validation (1-10 tags, 1-10 links)
|
||||
- `WebhookPayloadSchema`: Webhook request validation with API key auth
|
||||
- `KeywordInputSchema`: Keyword cloud data with visual config
|
||||
- `ProjectQuerySchema`: Query parameter validation (search, tags, status, pagination)
|
||||
- `ExternalLinkSchema`: URL validation with http/https protocol check
|
||||
- `TaskStatusEnum`: Discovery task states (PENDING/IN_PROGRESS/COMPLETED/FAILED)
|
||||
|
||||
### Prisma Client (`prisma.ts`)
|
||||
|
||||
**Purpose**: Singleton database client pattern
|
||||
|
||||
```typescript
|
||||
import { prisma } from "@/lib/prisma";
|
||||
```
|
||||
|
||||
### Utilities
|
||||
|
||||
- `utils.ts`: `cn()` - Tailwind class merging with clsx/twMerge
|
||||
- `slug.ts`: `generateSlug()` - URL-friendly slug generation (prefers English, max 100 chars)
|
||||
|
||||
### GitHub Integration
|
||||
|
||||
- `github/api.ts`: `getGitHubStats()` - Fetch repo stats (stars, forks, license) with 5min cache
|
||||
- `github/badges.ts`: `parseGitHubUrl()`, `getGitHubStarsBadgeUrl()`, `getAllGitHubBadgeUrls()`
|
||||
|
||||
## Usage Patterns
|
||||
|
||||
**Validation**:
|
||||
|
||||
```typescript
|
||||
import { ProjectInputSchema } from "@/lib/validations";
|
||||
const validated = ProjectInputSchema.parse(inputData);
|
||||
```
|
||||
|
||||
**Database**:
|
||||
|
||||
```typescript
|
||||
import { prisma } from "@/lib/prisma";
|
||||
const projects = await prisma.project.findMany();
|
||||
```
|
||||
|
||||
**GitHub Badges**:
|
||||
|
||||
```typescript
|
||||
import { getGitHubBadgesFromLinks } from "@/lib/github/badges";
|
||||
const { stars } = getGitHubBadgesFromLinks(project.externalLinks);
|
||||
```
|
||||
|
||||
## Key Design Decisions
|
||||
|
||||
- Singleton Prisma client prevents connection pool exhaustion in dev
|
||||
- All enums use Zod for runtime type checking
|
||||
- API key minimum length: 32 characters
|
||||
- URL validation enforces http/https protocol only
|
||||
Reference in New Issue
Block a user