Files
chat-one-service/README.md
alboped 6cc89062e1 feat(client): 短信登录、JWT、Redis 与 Spug 短信及流式 Chat
- 新增客户端认证:短信发送/登录、access/refresh JWT、Guard/Strategy\n- Redis 存验证码;可配置 SMS_CODE_TTL_SECONDS;失败时回滚与明确错误\n- 短信改为 Spug 推送助手(code/targets/number/name),移除 UniSMS\n- Chat SSE 接口与 DTO;AppModule 挂载 RedisModule\n- 更新 README 与 project-solution 环境变量说明

Made-with: Cursor
2026-04-21 06:30:50 +08:00

241 lines
7.3 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.
# chat-one-service
## TODO当前迭代
- [ ] client-app短信登录 + JWT 鉴权(接入真实短信服务前先 mock
- [ ] client-appChat 会话与消息持久化(接入 Prisma + 数据库)
- [ ] client-app按用户限流与基础风控基于 Redis 后续补上)
- [ ] admin-app邮箱登录与 RBAC角色/权限点基础能力)
- [ ] admin-app平台管理接口增删改查 + 开关 + 权重)
- [ ] admin-app用量统计与简单报表按平台 / 用户聚合)
---
ChatOne 服务端:基于 **NestJS 11** + **Fastify**,整合多厂商大模型对话能力,对外提供统一的 **SSEServer-Sent Events** 流式输出协议,便于 Web / App 接入。
更完整的架构说明见:`docs/project-solution.md`。JWT 最小示例见:`docs/jwt-minimal-nestjs.md`
---
## 技术栈
- **框架**NestJS 11`@nestjs/platform-fastify`
- **HTTP 客户端**`undici`(调用各厂商 OpenAI 兼容接口)
- **配置**`@nestjs/config`(可选环境校验见 `src/config/validation.ts`,默认可在 `AppModule` 中关闭)
- **日志**`nestjs-pino` + `pino-pretty`(开发环境美化输出)
- **文档**Swagger默认路径 `/docs`
- **安全头**`helmet`
---
## 目录结构(概要)
```text
src/
├── main.ts # 入口Fastify + 全局前缀 api + Swagger
├── app.module.ts # 根模块
├── config/ # 配置加载与环境校验
├── apps/
│ ├── client-app/ # 用户端(当前含 Chat SSE
│ ├── admin-app/ # 管理端(占位模块,后续扩展)
│ └── shared-domain/
│ └── ai-gateway/ # 多平台 Provider 与路由
├── prisma/ # Prisma 封装(按需接入数据库时再挂回 AppModule
docs/
├── project-solution.md
└── jwt-minimal-nestjs.md
```
---
## 环境要求
- **Node.js**:建议 20 LTS 及以上
- **包管理**:本项目使用 **Yarn**(存在 `yarn.lock`);亦可用 npm
---
## 安装依赖
```bash
yarn install
```
---
## 环境变量
在项目根目录创建 `.env`(该文件已在 `.gitignore` 中,**不要提交到 Git**)。
### 服务
| 变量 | 说明 | 示例 |
|------|------|------|
| `PORT` | 监听端口 | `3000` |
| `NODE_ENV` | 运行环境 | `development` / `production` |
### 千问DashScope OpenAI 兼容)
| 变量 | 说明 |
|------|------|
| `QWEN_API_KEY` | 千问 API Key |
| `QWEN_BASE_URL` | 可选,默认 `https://dashscope.aliyuncs.com/compatible-mode/v1` |
### DeepSeek
| 变量 | 说明 |
|------|------|
| `DEEPSEEK_API_KEY` | DeepSeek API Key |
| `DEEPSEEK_BASE_URL` | 可选,默认 `https://api.deepseek.com/v1` |
### 火山引擎(方舟 OpenAI 兼容形态,具体以你控制台为准)
| 变量 | 说明 |
|------|------|
| `VOLC_API_KEY` | 火山引擎 API Key |
| `VOLC_BASE_URL` | 可选,默认 `https://ark.cn-beijing.volces.com/api/v3` |
### Spug 推送助手(短信验证码)
在 [Spug 推送助手](https://push.spug.cc) 创建「短信验证码」类消息模板复制模板编号URL 路径中的 ID。模板中可使用变量 **`number`**(有效期,单位:**分钟**);服务端会根据 `SMS_CODE_TTL_SECONDS` 换算后传入(向上取整,至少为 1与 Redis 中验证码 TTL 一致。
| 变量 | 说明 |
|------|------|
| `SPUG_PUSH_SMS_TEMPLATE_ID` | 消息模板编号(必填,非 mock 时) |
| `SPUG_PUSH_BASE_URL` | 可选,默认 `https://push.spug.cc` |
| `SPUG_SMS_NAME` | 可选,模板若要求 `name` 变量则配置(与官方示例一致) |
| `SMS_MOCK` | 可选,`true` 时跳过真实短信发送(本地联调用) |
| `SMS_CODE_TTL_SECONDS` | 可选,短信验证码 Redis TTL默认 `300` |
> 说明:当前各 Provider 对上游采用 **非流式** `chat/completions` 调用,由网关将完整回复 **切片** 后以 SSE 推给客户端。后续可升级为上游真流式。
---
## 常用脚本
| 命令 | 说明 |
|------|------|
| `yarn start:dev` | 开发模式(`tsx watch`,改代码自动重启) |
| `yarn build` | TypeScript 编译到 `dist/` |
| `yarn start` | 运行已编译产物 `dist/main.js` |
| `yarn lint` | ESLint需本地配置规则时生效 |
---
## 启动
开发:
```bash
yarn start:dev
```
默认监听:`http://localhost:3000`(可通过 `PORT` 修改)。
生产(先编译再启动):
```bash
yarn build
yarn start
```
---
## API 说明
### Swagger
浏览器打开:`http://localhost:3000/docs`
### 客户端认证MVP
- `POST /api/client/v1/auth/sms/send`
- 入参:`{ "phone": "13800000000", "scene": "login" }`
- 返回:`requestId``expireIn``provider`
- 说明:已接入 Spug 推送助手;非生产环境会额外返回 `testCode` 便于联调
- `POST /api/client/v1/auth/sms/login`
- 入参:`{ "phone": "13800000000", "code": "xxxxxx" }`
- 返回:`accessToken``refreshToken``user`
- `POST /api/client/v1/auth/refresh`
- 入参:`{ "refreshToken": "..." }`
- 返回:新的 `accessToken``refreshToken`
> 验证码当前已接入 Redis 存储key: `chatone:client:sms:code:{phone}:{scene}`TTL 300 秒)。
### 统一 SSE Chat用户端
- **路径**`POST /api/client/v1/chat/completions/stream`
- **Content-Type**`application/json`
- **响应**`text/event-stream`SSE
#### 请求体(示例)
```json
{
"model": "qwen-plus",
"platform": "qwen",
"messages": [
{ "role": "system", "content": "你是一个乐于助人的助手" },
{ "role": "user", "content": "你好" }
]
}
```
- `platform``qwen` | `deepseek` | `volc` | `auto`(或不传,由路由按 `model` 简单匹配)
- `model`:各平台实际模型名或 Endpoint ID火山侧请填你在控制台配置的模型标识
#### SSE 事件约定
| 事件名 | data 字段含义 |
|--------|----------------|
| `meta` | 请求元信息:`requestId``platform``model` |
| `delta` | 文本增量:`{"delta":"..."}` |
| `usage` | Token 用量:`promptTokens` / `completionTokens` / `totalTokens` |
| `done` | 结束:`finishReason` |
#### curl 示例(流式)
先获取 token
```bash
curl -s -H "Content-Type: application/json" -X POST \
-d '{"phone":"13800000000","code":"123456"}' \
http://localhost:3000/api/client/v1/auth/sms/login
```
再带 `Authorization` 调用 chat
```bash
curl -N \
-H "Authorization: Bearer 你的accessToken" \
-H "Content-Type: application/json" \
-X POST \
-d '{"platform":"qwen","model":"qwen-plus","messages":[{"role":"user","content":"你是谁"}]}' \
http://localhost:3000/api/client/v1/chat/completions/stream
```
---
## 数据库与 Prisma
仓库内已包含 `src/prisma/` 模块骨架。若尚未准备好 PostgreSQL 或未执行 `prisma generate`,请勿在 `AppModule` 中导入 `PrismaModule`,避免启动时报缺少生成客户端的错误。
接入数据库时的典型步骤:
1. 编写 `prisma/schema.prisma` 并配置 `DATABASE_URL`
2. 执行 `npx prisma generate` / `yarn prisma generate`
3.`src/app.module.ts` 中按需 `imports: [PrismaModule]`
---
## 安全提示
- **切勿**将含真实 Key 的 `.env` 提交到版本库。
- 若密钥曾在公开场合暴露,请在对应云厂商控制台 **轮换 API Key**
---
## 许可证
MIT见仓库根目录 `LICENSE`)。