从 AGENTS.md 读懂 prompts.chat:AI 编码代理视角下的 Next.js + Prisma 开发规范与自托管配置体系
本篇基于 prompts.chat 仓库根目录的 AGENTS.md 指南展开,该系统化约定专为 AI 编码代理(如 Claude Code)设计,但也适用于任何人工开发者。读完本文,你将掌握该项目的技术栈全貌、目录结构、常用命令、代码风格约定、prompts.config.ts 配置体系、认证/存储插件架构与国际化机制,并能对照源码理解每项规范背后的实现依据,在自托管部署或二次开发时快速做出正确的技术决策。
项目定位与技术栈
AGENTS.md 开篇即给出项目定义:prompts.chat 是一个基于 Next.js 16 构建的 AI 提示词社交平台,允许用户分享、发现与收藏社区提示词;项目开源且支持自托管,可自定义品牌、主题与认证方式(原身为 Awesome ChatGPT Prompts)。
文档明确列出的技术栈如下(版本对照 package.json 实际依赖):
| 维度 | 技术选型 | 仓库实际依赖 |
|---|---|---|
| 框架 | Next.js 16.0.7(App Router) | next ^16.0.10 |
| 语言 | TypeScript 5 | typescript ^5 |
| 数据库 | PostgreSQL + Prisma ORM 6.19 | @prisma/client ^6.19.0 |
| 认证 | NextAuth.js 5(beta)+ 可插拔提供方 | next-auth ^5.0.0-beta.30 |
| 样式 | Tailwind CSS 4 + Radix UI 原语 | tailwindcss ^4,17 个 @radix-ui/* 包 |
| UI 组件 | shadcn/ui 模式(src/components/ui/) |
class-variance-authority + tailwind-merge |
| 国际化 | next-intl,多语言 | next-intl ^4.5.8 |
| 图标 | Lucide React | lucide-react ^0.556.0 |
| 表单 | React Hook Form + Zod 校验 | react-hook-form ^7.68.0 + zod ^4.1.13 |
从 package.json 的 engines 字段看,项目要求 Node.js 24.x 运行环境,这是自托管部署时的重要前提。
项目目录结构
文档给出的结构树是理解代码组织的地图,核心目录及其职责如下:
/
├── prisma/ # 数据库 schema 与迁移
│ ├── schema.prisma # Prisma schema 定义
│ ├── migrations/ # 数据库迁移
│ └── seed.ts # 数据库种子脚本
├── public/ # 静态资源(logo、favicon)
├── messages/ # i18n 翻译文件(en.json、es.json 等)
├── src/
│ ├── app/ # Next.js App Router 页面
│ │ ├── (auth)/ # 认证页面(login、register)
│ │ ├── [username]/ # 用户主页
│ │ ├── admin/ # 管理后台
│ │ ├── api/ # API 路由
│ │ ├── categories/ # 分类页
│ │ ├── prompts/ # 提示词 CRUD 页面
│ │ ├── feed/ # 用户信息流
│ │ ├── discover/ # 发现页
│ │ ├── settings/ # 用户设置
│ │ └── tags/ # 标签页
│ ├── components/ # React 组件
│ │ ├── admin/ # 管理端组件
│ │ ├── auth/ # 认证组件
│ │ ├── categories/ # 分类组件
│ │ ├── layout/ # 布局组件(header 等)
│ │ ├── prompts/ # 提示词相关组件
│ │ ├── providers/ # React Context 提供者
│ │ ├── settings/ # 设置组件
│ │ └── ui/ # shadcn/ui 基础组件
│ ├── lib/ # 工具库
│ │ ├── ai/ # AI / OpenAI 集成
│ │ ├── auth/ # NextAuth 配置
│ │ ├── config/ # 配置类型定义
│ │ ├── i18n/ # 国际化设置
│ │ ├── plugins/ # 插件系统(auth、storage)
│ │ ├── db.ts # Prisma client 实例
│ │ └── utils.ts # 工具函数(cn)
│ └── i18n/ # i18n 请求处理器
├── prompts.config.ts # 主应用配置
├── prompts.csv # 社区提示词数据源
└── package.json # 依赖与脚本
对照仓库实际内容可以看到,src/app/ 下还存在 book/、kids/、collection/、workflows/ 等文档结构树未列出的业务路由,说明文档的结构树聚焦于核心社交功能骨架,属于"主干视图"而非完整清单。
常用开发命令
文档列出的命令均能在 package.json 的 scripts 中一一对应,可复制直接运行:
# 开发
npm run dev # 启动开发服务器(localhost:3000)
npm run build # 生产构建(先执行 prisma generate)
npm run start # 启动生产服务器
npm run lint # 运行 ESLint
# 数据库
npm run db:generate # 生成 Prisma Client
npm run db:migrate # 执行数据库迁移
npm run db:push # 将 schema 变更推送到数据库
npm run db:studio # 打开 Prisma Studio
npm run db:seed # 用初始数据填充数据库
# 类型检查
npx tsc --noEmit # 不产出发包文件、仅检查 TypeScript 类型
# 翻译
node scripts/check-translations.js # 检查各语言缺失的翻译项
值得注意的是两点与文档的对应关系:
npm run build实际为prisma generate && next build的链式命令,即构建前自动重新生成 Prisma Client,这与postinstall: prisma generate形成双保险;- 文档未列出但仓库实际存在
npm run db:setup(prisma generate && prisma migrate dev && prisma db seed)与npm run setup(执行 scripts/setup.js),自托管首次初始化时可优先使用这两个一键脚本。
代码风格约定
TypeScript 命名与类型规则
文档对类型系统的要求相当具体:
- 使用 TypeScript strict 模式;
- 优先显式类型,避免
any; - 对象形状用
interface,联合/交叉类型用type; - 函数命名
camelCase(如getUserData、handleSubmit); - 组件命名
PascalCase(如PromptCard、AuthContent); - 真正的常量用
UPPER_SNAKE_CASE; - 文件命名:组件用
kebab-case.tsx,工具用camelCase.ts。
对照仓库可以印证这一约定:src/lib/db.ts 使用 camelCase 文件名导出单例,而 src/components/prompts/prompt-card.tsx 等组件均采用 kebab-case 文件名、PascalCase 组件名。
React / Next.js 约定
- 默认使用 React Server Components;
- 仅在需要客户端交互时添加
"use client"指令; - 变更类操作优先使用 Server Actions 而非 API 路由;
- 所有用户可见文案必须走 next-intl,禁止硬编码文本;
- 通过
useTranslations()或getTranslations()导入翻译。
文档给出的组件模式示例:
// 客户端组件示例
"use client";
import { useTranslations } from "next-intl";
import { Button } from "@/components/ui/button";
interface MyComponentProps {
title: string;
onAction: () => void;
}
export function MyComponent({ title, onAction }: MyComponentProps) {
const t = useTranslations("namespace");
return (
<div className="space-y-4">
<h2 className="text-lg font-semibold">{title}</h2>
<Button onClick={onAction}>{t("actionLabel")}</Button>
</div>
);
}
这个示例浓缩了四个核心模式:显式 Props 接口(interface + PascalCase)、命名函数导出(非默认导出)、shadcn 组件复用(@/components/ui/button)、next-intl 命名空间翻译。
样式与数据库约定
样式方面要求使用 Tailwind 工具类、遵循移动优先响应式(sm: / md: / lg: 断点)、用 cn() 工具函数(来自 @/lib/utils)处理条件类名、优先通过 shadcn/ui 组件使用 Radix 原语,并保持组件样式的作用域与可组合性。
数据库方面:
- 统一从
@/lib/db使用 Prisma Client; - 关联查询必须显式
select或include; - 多步操作用事务包裹;
- 高频查询字段加索引。
从源码看,src/lib/db.ts 的实现印证了工程细节:PrismaClient 通过 globalThis 挂单例防止热重载时连接池耗尽,日志级别在开发环境输出 query/error/warn、生产环境仅 error,并通过 datasourceUrl: process.env.DATABASE_URL 显式注入连接串。
prompts.config.ts 配置体系
文档将 prompts.config.ts 定义为主配置文件,包含 branding(Logo/名称/描述)、theme(颜色/圆角/UI 变体)、auth(认证提供方数组)、i18n(语言与默认语言)、features(功能开关)、homepage(首页定制与赞助商)六大板块。
对照当前仓库的实际配置,各板块取值如下:
export default defineConfig({
// 品牌 - 白标定制
branding: {
name: "prompts.chat",
logo: "/logo.svg",
logoDark: "/logo-dark.svg",
favicon: "/logo.svg",
description: "Collect, organize, and share AI prompts",
},
// 主题 - 设计系统配置
theme: {
radius: "sm", // 圆角: "none" | "sm" | "md" | "lg"
variant: "default", // UI 风格: "flat" | "default" | "brutal"
density: "default", // 间距密度: "compact" | "default" | "comfortable"
colors: {
primary: "#6366f1", // Indigo(支持 hex 或 oklch)
},
},
// 认证插件
auth: {
providers: ["github", "google", "apple"], // 可启用多个提供方
allowRegistration: false, // 是否允许公开注册(仅 credentials 生效)
},
// 国际化
i18n: {
locales: ["en", "tr", "es", "zh", "ja", "ar", "pt", "fr", "it", "de", "nl", "ko", "ru", "he", "el", "az", "fa"],
defaultLocale: "en",
},
// 功能开关
features: {
privatePrompts: true, // 私有提示词
changeRequests: true, // 版本变更请求系统
categories: true, // 分类
tags: true, // 标签
aiSearch: true, // AI 语义搜索(需 OPENAI_API_KEY)
aiGeneration: true, // AI 生成能力(需 OPENAI_API_KEY)
mcp: true, // MCP(Model Context Protocol)功能
comments: true, // 评论
},
// 首页定制
homepage: {
useCloneBranding, // true 时隐藏原项目品牌、启用自有品牌
achievements: { enabled: !useCloneBranding },
sponsors: {
enabled: !useCloneBranding,
items: [/* 赞助商 logo 与链接数组 */],
},
},
});
两处文档与实际配置的差异值得说明:
- 功能开关数量:文档提到 5 个开关(privatePrompts、changeRequests、categories、tags、aiSearch),当前配置实际有 8 个,新增了
aiGeneration、mcp、comments。类型定义 src/lib/config/index.ts 中后三者均为可选(?),说明它们是后加功能,保持向后兼容。 - 语言数量:文档写"11 种受支持语言",但当前 prompts.config.ts 的
locales数组与 messages/ 目录实际包含 17 个语言文件(新增了 nl、ru、he、el、az、fa),本文以仓库现状 17 种为准。
配置加载与 PCHAT_ 环境变量覆盖
文档未展开、但对自托管部署极为关键的一点:配置并非"读一次就结束"。从源码 src/lib/config/index.ts 看,getConfig() 在加载用户配置后会调用 applyEnvOverrides(),支持一套 PCHAT_ 前缀的环境变量在运行时覆盖配置文件,官方注释明确说明其目的是"通过 Docker 环境变量定制而无需重新构建":
| 环境变量 | 覆盖目标 |
|---|---|
PCHAT_NAME / PCHAT_DESCRIPTION / PCHAT_LOGO / PCHAT_LOGO_DARK / PCHAT_FAVICON |
品牌字段 |
PCHAT_THEME_RADIUS / PCHAT_THEME_VARIANT / PCHAT_THEME_DENSITY |
主题 |
PCHAT_COLOR |
主题主色 |
PCHAT_AUTH_PROVIDERS(逗号分隔)/ PCHAT_ALLOW_REGISTRATION |
认证 |
PCHAT_LOCALES(逗号分隔)/ PCHAT_DEFAULT_LOCALE |
国际化 |
PCHAT_FEATURE_*(如 PCHAT_FEATURE_AI_SEARCH,true/false) |
功能开关 |
一个有趣的细节:一旦设置了 PCHAT_NAME(src/lib/config/index.ts),homepage 会被强制切换为 clone 品牌模式(隐藏成就与赞助商区块)。配置还带进程级缓存,客户端组件需通过 getConfigSync() 读取,且必须在服务端组件先调用过 getConfig() 完成初始化,否则会抛出 "Config not initialized" 错误。
插件架构:认证与存储
文档指出认证与存储采用插件架构。从 src/lib/plugins/registry.ts 的实现看,这是一套基于 Map 的轻量全局注册表:插件以 id 为键注册(registerAuthPlugin / registerStoragePlugin),运行时通过 getAuthPlugin(id) 等函数按 id 取用,另有 getAll*Plugins() 用于枚举。
内置认证插件由 src/lib/plugins/auth/index.ts 统一注册,文档列出 4 个,当前仓库实际为 7 个:
| 插件文件 | 说明 |
|---|---|
| credentials.ts | 邮箱/密码认证 |
| github.ts | GitHub OAuth |
| google.ts | Google OAuth |
| azure.ts | Microsoft Entra ID |
| apple.ts | Apple 登录(文档未列) |
| oidc.ts | 通用 OIDC(文档未列) |
| oauth.ts | 通用 OAuth(文档未列) |
这与 prompts.config.ts 中 providers 注释"可用值:credentials / google / azure / github / apple / oidc / oauth / 自定义"完全吻合,也解释了为什么 AuthProvider 类型(src/lib/config/index.ts)被定义为联合字符串加 string 的开放式类型——为自定义插件留了口子。
存储插件方面,文档列出 url.ts(基于 URL 的媒体,默认)与 s3.ts(AWS S3),当前 src/lib/plugins/storage/ 目录还包含 do-spaces.ts(DigitalOcean Spaces),共 3 个内置实现,供自托管时按基础设施选择媒体存储后端。
国际化机制
文档对 i18n 的约定:
- 翻译文件位于
messages/{locale}.json; - 新增语言三步走:在 prompts.config.ts 的
i18n.locales数组中加入语言代码 → 在messages/下创建对应翻译文件 → 在 src/components/layout/header.tsx 的语言选择器中加入该语言; - 配套校验工具 scripts/check-translations.js 可扫描各语言间的缺失翻译项。
对照 messages/ 目录,当前仓库有 17 个 JSON 文件(ar、az、de、el、en、es、fa、fr、he、it、ja、ko、nl、pt、ru、tr、zh),比文档写定的 11 种多 6 种,印证了该列表处于持续扩充中。
关键文件速查
文档给出的 Key Files 表是快速定位入口的索引,全部路径均已在仓库中确认存在:
| 文件 | 用途 |
|---|---|
| prompts.config.ts | 主应用配置 |
| prisma/schema.prisma | 数据库 schema |
| src/lib/auth/index.ts | NextAuth 配置 |
| src/lib/db.ts | Prisma Client 单例 |
| src/app/layout.tsx | 根布局(挂载全局 providers) |
| src/components/ui/ | shadcn 基础 UI 组件 |
开发边界:Always / Ask First / Never
文档最具"代理协作契约"色彩的章节,把行为划分为三档:
始终要做(Always Do)
- 提交前运行
npm run lint; - 复用
src/components/ui/中的现有 UI 组件; - 为所有用户可见文本补充翻译;
- 遵循现有代码模式与文件结构;
- 使用 TypeScript strict 类型。
先问再做(Ask First)
- 数据库 schema 变更(需要迁移);
- 新增依赖;
- 修改认证流程;
- 变更
prompts.config.ts的结构。
绝不做(Never Do)
- 提交密钥或 API Key(一律走
.env); - 修改
node_modules/或生成文件; - 删除现有翻译;
- 移除或弱化 TypeScript 类型;
- 硬编码用户可见字符串(必须走 i18n)。
这套边界与仓库实践自洽:prisma/migrations/ 下有 30 余个带时间戳的迁移目录,证明 schema 变更严格走迁移流程;prompts.config.ts 中 defineConfig 的类型约束(src/lib/config/index.ts)从编译层面强制配置结构不可随意变形。
环境变量
文档给出的 .env 变量清单:
必填两项:
DATABASE_URL= # PostgreSQL 连接串
AUTH_SECRET= # NextAuth 密钥
使用对应 OAuth 提供方时的可选项:
AUTH_GITHUB_ID=
AUTH_GITHUB_SECRET=
AUTH_GOOGLE_ID=
AUTH_GOOGLE_SECRET=
AUTH_AZURE_AD_CLIENT_ID=
AUTH_AZURE_AD_CLIENT_SECRET=
AUTH_AZURE_AD_ISSUER=
可选功能项:
OPENAI_API_KEY= # 启用 AI 驱动的语义搜索
结合源码可以补全使用逻辑:DATABASE_URL 被 src/lib/db.ts 显式读取并注入 PrismaClient;OPENAI_API_KEY 与 prompts.config.ts 中的 aiSearch / aiGeneration 开关是配套关系——开关开启但缺少 Key 时 AI 能力不可用,因此自托管时二者需同时评估。
测试策略与常见任务清单
文档的 Testing 章节原文写"目前无自动化测试",但当前仓库状态已超出这一描述:package.json 配齐了 test / test:watch / test:ui / test:coverage 四个 vitest 脚本,且 src/__tests__/ 与 packages/ 下合计已有 50 个测试文件(覆盖 API 路由、lib 工具、hooks 与 packages/prompts.chat 子包)。文档给出的测试约定(测试文件放在源码旁或 __tests__/ 目录、使用描述性命名、mock 数据库与 OAuth 等外部服务)依然是新增测试时应当遵循的规范。
文档最后以 Common Tasks 收尾,给出四件高频操作的步骤清单:
新增页面
- 在
src/app/{route}/page.tsx创建路由; - 数据获取用 Server Component;
- 为所有文案在
messages/*.json中补充翻译。
新增组件
- 放入合适的
src/components/{category}/目录; - 从组件文件直接导出(无需 barrel 导出);
- 遵循现有组件模式。
新增 API 路由
- 创建
src/app/api/{route}/route.ts; - 导出对应 HTTP 方法处理器(GET、POST 等);
- 请求校验用 Zod;
- 返回带正确状态码的 JSON 响应。
修改数据库 schema
- 更新 prisma/schema.prisma;
- 运行
npm run db:migrate生成迁移; - 视需要更新相关 TypeScript 类型。
小结
AGENTS.md 的价值在于它把"如何让 AI 代理(以及新加入的人类开发者)安全地修改这个代码库"压缩成了可执行契约:技术栈与版本约束划定运行前提,结构树与命令表提供导航与操作入口,风格规则约束日常编码,配置体系(含 PCHAT_ 运行时覆盖)支撑白标自托管,插件注册表解耦认证与存储后端,三档边界清单划定变更风险等级。需要提醒的是,文档中"11 种语言"与"无自动化测试"等描述相对当前仓库已有演进(实际 17 种语言、50 个测试文件、7 个认证插件),以本文标注的仓库现状为准。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00