465 lines
20 KiB
Markdown
465 lines
20 KiB
Markdown
# 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
|