Files
OCS_service/CLAUDE.md
T
jiawei 90412a3688
ocs-nuxt / deploy (push) Successful in 1m46s
feat: 新增用户管理
2026-05-24 23:26:43 +08:00

204 lines
14 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
## 项目定位
本项目是基于 Nuxt 4 / Nitro 的 OCS AI 答题服务,兼容 OCS AnswererWrapper 的题库接口,同时提供网页登录、答题工作台、Dashboard、个人 API 配置和 superadmin 系统配置后台。
核心技术栈:
- Nuxt 4、Vue 3、Pinia、VueUse、Tailwind CSS v4、shadcn-vue / reka-ui、lucide-vue-next。
- Better Auth 邮箱密码登录,Prisma 7 + `@prisma/adapter-mariadb` 连接 MySQL/MariaDB。
- OpenAI 兼容 Chat Completions 流式调用;对 OCS 客户端仍返回普通 JSON。
- pnpm 10.33.0Node 22 Alpine 用于 Docker 镜像。
## 核心原则
- 默认最小改动,优先复用现有目录结构、工具函数、共享类型、store 和 service。
- 前端不接触数据库连接串、session 细节、完整 API Key、token、cookie 或上游响应体。
- API 返回给前端或 OCS 的 `msg` 必须是本地业务表达,不暴露 OpenAI、Better Auth、Prisma、token、key、连接串或调试细节。
- 内部异常统一返回“服务器内部错误”;具体异常只能进入服务端安全日志。
- 日志记录 requestId、阶段、用户/记录标识、分页、耗时、状态等排查信息;不得记录密码、cookie、完整 key、token、完整 prompt、图片二进制、base64、完整请求体或响应体。
- 不写可能阻塞整个进程的代码;流、DB、外部请求都要有明确边界或错误出口。
- 不为未来不确定需求预建兼容路由、抽象层、配置项或多套入口。
## 目录结构约定
- `app/`:前端应用代码。
- `app/pages/`:页面路由,当前包括首页答题、Dashboard、登录、注册。
- `app/components/`:业务组件;`app/components/ui/` 是 shadcn-vue 组件,尽量不要手改生成件。
- `app/services/`:前端 API 封装,组件不要直接写 `$fetch` 调业务接口。
- `app/stores/`:Pinia 状态与动作;组件通过 store 消费状态和发起业务操作。
- `app/interfaces/`:前端类型出口,主要重导出 `shared/types`
- `app/utils/`:前端工具,例如 Better Auth client、错误文案、剪贴板等。
- `server/`Nitro 服务端代码。
- `server/api/`JSON API 与 Better Auth 路由。
- `server/middleware/`:服务端中间件,当前包含 API 统一鉴权和注册开关守卫。
- `server/plugins/`:Nitro 启动插件,当前用于补全默认系统配置。
- `server/utils/`:服务端业务工具、DB、鉴权、OpenAI、日志、配置、答题逻辑。
- `shared/`:前后端共享类型和纯函数。新增或修改接口契约时优先更新这里。
- `prisma/schema.prisma`:数据库结构唯一来源;Prisma Client 输出到 `prisma/generated`,不要改回 `app/generated`
- `public/`:静态公开文件,不经过构建处理。
## 认证与权限
- Better Auth 实例在 `server/utils/auth.ts`,使用 Prisma MySQL/MariaDB 适配器,只启用邮箱密码登录。
- 注册用户时通过 Better Auth `databaseHooks` 自动生成 32 位 hex `apiToken`
- `apiToken` 供 OCS 油猴脚本跨域调用 `/api/search` 使用;客户端不能自行写入,刷新走 `POST /api/user/refresh-token`
- `server/middleware/api-auth.ts` 默认保护所有 `/api/*` 路由;只有 `publicApiRoutes` 中声明的公开路由放行。
- 当前公开路由:
- `/api/auth/**`Better Auth 登录、注册、退出、get-session 等。
- `GET /api/health`:健康检查,不含敏感信息。
- `/api/search`:有自己的 session/apiToken 双通道鉴权。
- `OPTIONS` 预检请求在中间件中直接返回 204。
- superadmin 接口必须在 handler 内二次校验 `role === "superadmin"`,不能只依赖通用 middleware。
- 注册开关由 `allow_registration` 系统配置控制,`server/middleware/registration-guard.ts` 拦截 `POST /api/auth/sign-up/email`
## API 规范
- 新增接口默认需要登录;只有确实公开的接口才能加入 `server/utils/api-auth-rules.ts`
- Handler 只负责入参校验、鉴权/权限边界、调用业务函数和统一响应;复用逻辑放到 `server/utils`
- 非 OCS 接口使用 `server/utils/response.ts`
- 成功:`apiOk(data)`,结构为 `{ code: 0, data, msg: "请求成功" }`
- 失败:`apiErr(code, msg)``data` 固定为 `null`
- `/api/search` 是 OCS 兼容接口,不使用 `apiOk/apiErr`
- 成功固定 `{ code: 1, question, answer }`
- 失败固定 `{ code: 0, msg }`
- 所有 JSON body 先校验为普通对象或 `null`;数组、字符串等无效 body 返回 400。
- 对客户端传入字段必须白名单过滤,只接受当前接口声明的字段和正确类型。
- 新增或修改接口时,同步维护 `shared/types`、服务端实现、前端 service、Pinia store 和组件消费。
- API 响应只返回前端需要的字段,不透出内部响应体、数据库异常、第三方错误详情或完整调试对象。
## 答题流程与缓存
- `/api/search` 兼容 GET、JSON POST、urlencoded POST、multipart/form-data。
- 鉴权顺序:优先读取网页登录 session;没有 session 时使用请求中的 `token``User.apiToken`
- `title/type/options` 会标准化为 `SearchParams`,只把题目长度、题型和是否有选项写日志。
- 缓存不再是进程内内存缓存;答案记录写入 `qa_record`,按 `userId + md5(title|type|options)` 查询最近答案。
- 清缓存不删除历史记录,而是更新 `User.cacheClearedAt`;缓存查询只命中该时间之后的记录。
- 调 OpenAI 前必须通过 `getUserEffectiveApiConfig(userId)` 取得生效配置,保证系统 key 不会发往用户自定义 endpoint。
- 多选题继续使用 `#` 分隔;`server/utils/answer.ts` 中的 OCS 响应格式不可随意改动。
## 配置模型
- OpenAI 运行配置以数据库 `system_config` 为准,不再依赖 `OPENAI_API_KEY` 等旧环境变量。
- `server/plugins/initConfig.ts` 启动时补全缺失的默认系统配置;不覆盖已有值。
- `server/utils/sysConfig.ts` 对系统配置做 60 秒 TTL 内存缓存;superadmin 更新配置后必须调用 `invalidateSysConfigCache()`
- 系统配置接口:
- `GET /api/admin/system-config`:仅 superadmin,可读,API Key 只返回遮蔽预览。
- `PUT /api/admin/system-config`:仅 superadmin,可写,`openAiApiKey` 为空字符串表示不修改已有 key。
- 用户自定义配置保存在 `user_config.value` JSON 中:
- `GET /api/user/settings`:只返回遮蔽后的 key 预览。
- `POST|PUT /api/user/settings`:白名单字段,空字符串 key 表示不修改旧 key。
- 用户启用自定义配置时,只有 `customApiBase``customApiKey` 同时非空,才使用用户 endpoint + key;否则 base 和 key 完全回退系统配置。
- `DATABASE_URL``BETTER_AUTH_SECRET``BETTER_AUTH_URL` 仍来自环境变量;`.env.example` 只放这些运行必需项。
## 数据库与 Prisma
- Prisma schema 位于 `prisma/schema.prisma`,实际数据库结构以 Prisma 为准。
- 当前使用 Prisma 7 + `@prisma/adapter-mariadb`Prisma Client 从 `server/utils/db.ts` 创建和复用。
- 业务代码不要直接 `new PrismaClient()`,不要在前端读取或间接获取数据库连接信息。
- `DATABASE_URL` 只允许服务端读取;日志和响应都不能输出完整连接串。
- `prisma.config.ts` 在 Prisma 命令加载时需要 `DATABASE_URL`Docker build 使用占位值,运行时由容器环境变量覆盖。
- 修改数据库结构的标准流程:
1. 先阅读 `prisma/schema.prisma`、相关 handler、`server/utils` 和共享类型。
2. 修改 schema。
3. 优先新增 Prisma migration;若当前开发库确认可接受 `prisma db push`,必须说明原因。
4. 运行 `.\node_modules\.bin\prisma.CMD generate` 重新生成客户端。
5. 对实际数据库执行同步命令,并确认 schema 已落库。
6. 运行类型检查;涉及服务启动或构建行为时再运行构建。
- 如果 migration 状态和数据库实际结构不一致,先停下来检查原因,不要直接强行部署或 resolve。
- 数据库不要保存大体积二进制、base64 或敏感明文;API Key 如需保存,只能服务端读取,前端只看遮蔽预览。
## 前端约定
- 组件只负责 UI 渲染和交互,通过 `useXxxStore()``storeToRefs()` 消费状态,通过 store action 发起操作。
- 接口调用放在 `app/services/`;业务状态、loading、错误文案和 toast 放在 Pinia store。
- Store 内部通用常量作为具名导出,供组件引用,不在组件中重复定义。
- 认证状态由 `app/plugins/auth.ts` 做 SSR/client 共用初始化,避免首屏水合不一致。
- `/dashboard``app/middleware/auth.ts` 保护,未登录跳 `/login`
- 深色模式通过 `useCookie("color-mode")` 持久化,避免 localStorage 导致 SSR 水合不匹配。
- 页面与组件不得展示内部服务名、第三方错误、token、key、连接串或原始异常信息。
- shadcn-vue 配置见 `components.json`;新增 UI 优先使用现有 `app/components/ui`、lucide 图标和 Tailwind token。
## 代码风格
- TypeScript 严格类型优先,避免 `any` 扩散;确需使用时收敛在边界处。
- 新增或大改 `server/` 文件时,文件顶部写一行中文用途说明,格式建议为 `// server/... - 用途说明`
- 复杂 `defineEventHandler` 上方写清楚流程、鉴权边界、数据是否入库、哪些信息不会返回前端。
- 注释使用中文,描述意图、边界和排查信息,不写机械解释。
- 不删除已有有价值注释;重写文件时保留或迁移原注释表达的信息。
- import 排序受 `eslint-plugin-simple-import-sort` 约束。
- `app/components/ui/**` 在 ESLint 中忽略,通常视为生成代码,不做无关手改。
## 常用命令
- 安装依赖:`pnpm install`
- 开发启动:`pnpm dev`
- 构建:`pnpm build`
- 预览构建产物:`pnpm preview`
- Nuxt 静态生成:`pnpm generate`
- Prisma generate`.\node_modules\.bin\prisma.CMD generate`
- 类型检查:`.\node_modules\.bin\nuxi.CMD typecheck`
- ESLint`.\node_modules\.bin\eslint.CMD .`
执行说明:
- 涉及 Prisma schema 时必须运行 Prisma generate。
- 涉及 API、共享类型、store、组件联动时至少运行类型检查。
- 涉及构建、Nitro 插件、Nuxt 配置、Docker 行为时再运行构建。
- 当前仓库未声明专门的 `test` 脚本,不要假设存在单元测试命令。
## Docker 与部署
- `Dockerfile.base` 基于 `node:22-alpine`,启用 corepack 并激活 pnpm 10.33.0。
- `Dockerfile``ocs-base:latest` 构建应用,复制源码、安装依赖、执行 `pnpm build`,最终用 `node .output/server/index.mjs` 启动。
- `.dockerignore` 排除 `node_modules/``.nuxt/``.output/``prisma/generated/`、本地 env 和日志。
- 容器默认 `PORT=3000``TZ=Asia/Shanghai`
- 构建阶段的 `DATABASE_URL` 是占位值;运行时必须提供真实数据库连接和 Better Auth 环境变量。
## 可用 Skills
本项目本地 `.agents/skills` 包含以下 Better Auth 相关 skills,遇到对应任务时优先查阅:
- `better-auth-best-practices`Better Auth 服务端/客户端、数据库适配、session、插件和环境变量。
- `create-auth-skill`:为 TypeScript/JavaScript 项目脚手架或扩展认证流程。
- `email-and-password-best-practices`:邮箱密码、邮箱验证、密码重置和密码策略。
- `better-auth-security-best-practices`:速率限制、secret、CSRF、trusted origins、cookie/session 安全和审计。
- `organization-best-practices`:组织、多租户、成员、邀请、团队和 RBAC。
- `two-factor-authentication-best-practices`:TOTP、OTP、备份码、可信设备和 2FA 登录流。
当前会话还可用的通用 skills / 插件能力:
- `frontend-design`:构建或美化前端页面、组件、应用体验。
- `openai-docs`:查询 OpenAI 官方文档和最新 API/模型建议。
- `imagegen``hatch-pet`:生成位图视觉素材或 Codex pet。
- `documents:documents``presentations:Presentations``spreadsheets:Spreadsheets`:处理 Word、PPT、表格文件。
- GitHub 插件 skills`github:github``github:gh-address-comments``github:gh-fix-ci``github:yeet`
- `skill-creator``skill-installer``plugin-creator`:创建/安装 Codex skills 或插件。
使用 skills 时先读对应 `SKILL.md`,只加载与当前任务直接相关的引用文件,不要为了普通代码改动批量读取全部资料。
## AI 执行清单
当新增或调整 API、数据结构、认证、配置或核心业务逻辑时,按以下顺序执行:
1. 阅读真实实现:handler、middleware、`server/utils``shared/types`、Pinia store、Prisma schema。
2. 明确鉴权边界:公开路由、session、apiToken、superadmin 二次校验。
3. 更新共享类型,再更新服务端、前端 service、store 和组件。
4. 对请求体做普通对象校验和字段白名单过滤。
5. 确认响应 `msg``data` 不包含内部或第三方细节。
6. 确认敏感信息不进入前端响应、日志或不该保存的数据库字段。
7. 涉及数据库时同步 schema、migration 或 db push、Prisma generate 和实际数据库。
8. 运行类型检查;涉及 Prisma schema 时必须 Prisma generate;涉及服务启动或构建行为时再构建。
## 非目标
- 不恢复旧的 `ACCESS_TOKEN` 单全局令牌模式。
- 不恢复旧的 OpenAI 环境变量配置作为主配置来源。
- 不为同一能力创建多个本地别名路由。
- 不新增长期保留的临时排查接口,例如数据库健康检查类接口。
- 不引入与当前需求无关的抽象层、兼容层或配置项。
- 不在多个地方维护同一配置值。
- 不保存大体积 base64、敏感明文或上游完整响应体。
- 不把服务端密钥、session、token、cookie、数据库连接信息或内部错误暴露给前端。