docs: 生成层次化 AGENTS.md 文档系统

This commit is contained in:
2026-02-01 14:57:43 +08:00
parent e1f250d397
commit 53e1faab89
5 changed files with 479 additions and 0 deletions
+46
View File
@@ -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
+60
View File
@@ -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
+49
View File
@@ -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
+66
View File
@@ -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