Files
aiartstudio/CLAUDE.md
T
2026-04-26 00:39:28 +08:00

158 lines
8.7 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
## 目标
本文档用于约束 AI 在本项目内的实现方式,确保代码简洁、可维护、安全,并与当前业务链路保持一致。
## 核心原则
- 默认最小改动,优先复用现有工具函数、类型和目录结构。
- 保持单一入口和单一职责,避免同一业务暴露多套路由或重复实现。
- 前端不接触 NewAPI session、完整 API Key、Lsky token 等敏感信息。
- 注释和日志要解释意图、边界和排查信息,不输出密码、cookie、完整 key、token、图片二进制或完整 prompt。
- 已存在的说明性注释不要随意删除,尤其是 `server/utils/openai.ts` 里的模型调用、视觉输入、流式解析等上下文注释。
## API 路由规范
- 认证相关接口统一放在 `server/api/auth`
- `POST /api/auth/register`
- `POST /api/auth/login`
- `GET /api/auth/me`
- `GET /api/auth/logout`
- `GET /api/auth/ready`
- 生图相关接口统一放在 `server/api/images`
- `POST /api/images/generate`
- `GET /api/images/history`
- `GET /api/images/history/:id`
- `DELETE /api/images/history/:id`
- `GET /api/images/stats`
- 不创建 `server/api/user` 之类的本地别名路由。
- 临时排查接口不要长期保留,例如数据库健康检查类接口排查结束后必须删除。
## 登录与环境准备
- 登录成功后,后端从 NewAPI `Set-Cookie` 中提取 `session`,写入本站 httpOnly cookie,同时保存 `newapi_user_id`
- 前端通过 `/api/auth/me` 恢复登录状态,通过 `/api/auth/logout` 清理登录状态。
- 登录成功后前端可调用 `/api/auth/ready`,用于确认当前 NewAPI 用户是否具备可用的 `AIArtStudio` Token。
- `/api/auth/ready` 只检查或创建环境:
- 只认 `name === "AIArtStudio"``status === 1`、未软删除的 Token。
- 没有可用 Token 时,后端按固定参数创建。
- 不调用完整 key 获取接口,不向前端返回 key。
- 返回文案使用“环境已准备 / 环境初始化完成”等业务表达,不暴露 API Key 细节。
- 完整 key 只允许在服务端真实调用模型前按需获取,相关逻辑集中在 `server/utils/newApiTokens.ts`
## 上游与模型调用
- 调用 NewAPI 用户、Token 等上游接口,使用 `server/utils/fetch.ts` 的统一入口:
- `newApiFetch`:普通未登录请求。
- `newApiFetchRaw`:需要读取上游响应头时使用,目前主要用于登录提取 `Set-Cookie`
- `newApiAuthedFetch`:需要 NewAPI 登录态时使用,由服务端从 httpOnly cookie 读取 session/userId 并补齐请求头。
- 生图模型调用集中在 `server/utils/openai.ts`
- 当前生图上游使用 `POST https://api.qflink.xyz/v1/chat/completions`,参数固定为:
- `model: "gpt-image-2"`
- `stream: true`
- `messages: [{ role: "user", content: prompt }]`
- 生图通过 `askImgStream` 读取 SSE 流,累积 `choices[].delta.content`,从 Markdown 图片或普通 URL 中提取图片地址。
- `askStream` 保留给 Responses API 的其他流式文本/多模态场景,不强行复用于 chat completions SSE。
- 不再使用 `/v1/images/generations` 作为当前生图主链路。
## 生图、图床与历史记录
- `POST /api/images/generate` 当前同步等待生图完成后返回,不向前端透传流式进度。
- 生图成功后返回:
- `imageUrl`:NewAPI 上游返回的图片 URL,前端当前优先展示。
- `hostedImageUrl`:Lsky 图床归档后的 URL,归档失败时为 `null`
- `revisedPrompt`:流式 chat completions 当前没有等价字段,通常为空。
- Lsky 归档逻辑集中在 `server/utils/lsky.ts`
- 配置从 `LSKY_BASE_URL``LSKY_TOKEN``LSKY_STORAGE_ID` 读取。
- 上传时先下载上游图片,再用 `multipart/form-data` 调 Lsky `/upload`
- 文件名格式为 `userId_username_timestamp_recordId.ext`
- tags 固定包含 `AIArtStudio``user:{userId}``record:{recordId}``model:gpt-image-2`
- 图床上传失败不影响本次生图成功:接口仍返回上游 `imageUrl`,数据库记录归档失败提示。
- 数据库不保存图片 base64;不要恢复 `image_base64` 或类似大文本存图方案。
- 历史列表不返回大体积数据;详情可返回完整上游响应和 Lsky 上传响应。
## 数据库与 Prisma
- Prisma schema 位于 `prisma/schema.prisma`,实际数据库同步以 Prisma 为准。
- 根目录 `create_tables.sql` 是人工可读建表参考,字段变更时必须同步更新。
- Prisma Client 从 `~~/app/generated/prisma/client` 引入,统一由 `server/utils/prisma.ts` 创建和复用。
- 当前使用 Prisma 7 + `@prisma/adapter-mariadb``DATABASE_URL` 在运行时解析为 MariaDB pool config。
- 登录或 `/api/auth/me` 成功后会 upsert `User` 快照,主键使用 NewAPI 用户 id。
- 生图记录写入 `ImageGeneration`
- 开始时写 `RUNNING`
- 成功时写 `SUCCEEDED`、上游 URL、图床 URL、MIME、完整上游响应、完整图床响应、耗时。
- 失败时写 `FAILED`、错误信息、耗时。
- 删除历史采用软删除 `deletedAt`
- `GenerationStats` 使用固定 id `global` 记录全局统计。
- 统计更新失败只记录日志,不应阻断用户拿到已经生成的图片。
- 需要变更数据库结构时,同时维护 Prisma migration 和 `create_tables.sql`
## 日志规范
- API handler 使用 `server/utils/logging.ts``createApiLogger``toSafeLogError`
- 日志必须包含足够排查信息,例如 `requestId`、阶段、`userId``recordId`、分页、耗时、状态。
- 生图日志阶段建议保持清晰:
- `read_body`
- `read_user_id`
- `create_running_record`
- `get_api_key`
- `call_image_stream_api`
- `upload_lsky`
- `finish_success_record`
- 不记录密码、cookie、完整 API key、Lsky token、完整 prompt、图片二进制、base64。
- 全局请求日志中间件只记录 method、path、status、耗时,不记录请求体和响应体。
## 请求、响应与错误处理
- 所有 JSON 接口先校验请求体:只接受 JSON 对象或 `null`,数组、字符串等无效 body 直接返回 400。
- 对上游透传字段必须使用白名单数组过滤,只透传类型正确且文档声明的字段。
- 统一使用 `createSuccessResponse``createErrorResponse` 返回结构。
- 上游异常统一通过 `createUpstreamErrorResponse` 转换。
- 401 或登录态失效时统一清理本地 auth cookie。
- 不在 handler 内重复实现复杂错误解析,通用判断放到 `server/utils`
## 类型规范
- 用户相关请求/响应类型放在 `shared/types/user.ts`
- 公共响应类型放在 `shared/types/index.ts`
- 生图、历史、统计、OpenAI 基础调用类型放在 `shared/types/openai.ts`
- 只有前后端共享的接口契约放入 `shared/types`;服务端内部上游适配类型留在 `server/utils` 或对应 handler 内。
- 新增或修改接口时先更新共享类型,再更新服务端和前端调用。
- 类型字段应有中文注释,说明含义、可选性和是否可能为空。
## 前端接入约定
- 用户服务在 `app/services/user_service.ts`,图片服务在 `app/services/image_service.ts`
- 登录成功后可以调用 `UserReady()` 准备环境;`/api/auth/me` 恢复登录状态时不自动调用 ready。
- 当前首页生图组件为 `app/components/ImageGenerateCom.vue`,优先展示响应中的 `imageUrl`
- `hostedImageUrl` 作为图床归档地址返回,后续需要切换展示来源时再调整前端策略。
## 代码风格
- TypeScript 严格类型优先,避免 `any` 扩散。
- 新增通用逻辑优先抽到 `server/utils`,handler 只负责入参校验、调用和统一响应。
- 修改优先小步快改,不重构无关代码。
- 注释使用中文,描述意图与边界,不写机械解释。
- 不删除已有有价值注释;确需重写文件时,要保留或迁移原注释表达的信息。
## AI 执行清单
当 AI 新增或调整 API 时,按以下顺序执行:
1. 先阅读现有 handler、utils、shared types、Prisma schema,确认真实实现。
2. 更新共享类型和服务端内部类型。
3. 在 handler 中完成请求体校验、白名单过滤、鉴权和日志。
4. 将可复用业务逻辑抽到 `server/utils`
5. 涉及数据库时同步修改 Prisma schema、migration、`create_tables.sql`
6. 确认敏感信息不进入前端响应、日志或数据库不该保存的字段。
7. 运行 `pnpm typecheck`;涉及 Prisma schema 时运行 `prisma generate`,必要时同步数据库。
## 非目标
- 不为未来不确定需求预建兼容路由。
- 不引入与当前需求无关的抽象层。
- 不在多个地方维护同一配置值。
- 不保存生成图片 base64。
- 不把服务端密钥、session 或 token 暴露给前端。