feat: 初始化 Nest 服务骨架与多平台 Chat SSE 网关
- 新增 NestJS + Fastify 入口、配置模块与 Swagger 集成 - 划分 client-app / admin-app 与 shared-domain ai-gateway - 实现统一 SSE Chat 接口,支持千问、DeepSeek、火山引擎非流式上游与网关分片输出 - 补充项目方案与 JWT 最小实现文档 Made-with: Cursor
This commit is contained in:
568
docs/project-solution.md
Normal file
568
docs/project-solution.md
Normal file
@@ -0,0 +1,568 @@
|
||||
# ChatOne Service 项目方案(NestJS)
|
||||
|
||||
本文给出一个主流且简洁、可直接落地的服务端方案,满足以下目标:
|
||||
- 基于 NestJS 构建;
|
||||
- 同时提供客户端接口与后台管理接口;
|
||||
- 支持短信登录、邮箱登录;
|
||||
- 支持千问、火山引擎、DeepSeek 等多平台 AI Chat 流式输出;
|
||||
- 对外提供统一调用接口(自动路由)和指定平台调用接口;
|
||||
- 提供用户管理、平台管理、用量统计。
|
||||
|
||||
---
|
||||
|
||||
## 1. 技术选型(主流且简洁)
|
||||
|
||||
- **运行时**:Node.js 20 LTS
|
||||
- **框架**:NestJS 10(Fastify 适配器,性能更优)
|
||||
- **ORM**:Prisma(类型安全、迁移友好)
|
||||
- **数据库**:PostgreSQL 15
|
||||
- **缓存/队列**:Redis 7(缓存、限流、验证码、会话黑名单)
|
||||
- **鉴权**:JWT(Access + Refresh)+ RBAC
|
||||
- **文档**:Swagger(`@nestjs/swagger`)
|
||||
- **校验**:`class-validator` + `class-transformer`
|
||||
- **日志**:Pino(`nestjs-pino`)
|
||||
- **任务调度**:`@nestjs/schedule`(统计聚合作业)
|
||||
- **流式输出**:SSE(标准 EventSource,前端接入简单)
|
||||
|
||||
---
|
||||
|
||||
## 2. 项目结构(推荐:按用户端/管理端强隔离)
|
||||
|
||||
```text
|
||||
chat-one-service/
|
||||
├─ src/
|
||||
│ ├─ main.ts # 单体双端统一启动入口(MVP)
|
||||
│ ├─ app.module.ts # 根模块:聚合 client/admin/shared
|
||||
│ ├─ common/
|
||||
│ │ ├─ constants/ # 全局常量(错误码前缀、header key 等)
|
||||
│ │ ├─ decorators/ # 自定义装饰器(当前用户、角色、公开路由)
|
||||
│ │ ├─ filters/ # 全局异常过滤(统一错误响应格式)
|
||||
│ │ ├─ guards/ # 通用 guard(按需被 client/admin 复用)
|
||||
│ │ ├─ interceptors/ # 请求日志、traceId、响应耗时统计
|
||||
│ │ ├─ pipes/ # DTO 校验与类型转换
|
||||
│ │ └─ utils/ # 通用工具函数(时间、脱敏、签名等)
|
||||
│ ├─ config/
|
||||
│ │ ├─ configuration.ts # 读取并组织配置(按模块导出)
|
||||
│ │ ├─ validation.ts # 启动前环境变量校验(fail fast)
|
||||
│ │ └─ swagger.ts # Swagger 初始化与分组(client/admin)
|
||||
│ ├─ apps/
|
||||
│ │ ├─ client-app/ # 用户端边界:面向 C 端业务能力
|
||||
│ │ │ ├─ client-app.module.ts # 用户端聚合模块(auth/chat/sessions/profile)
|
||||
│ │ │ ├─ auth/ # 用户端认证:短信验证码、登录、refresh
|
||||
│ │ │ ├─ chat/
|
||||
│ │ │ │ ├─ chat.module.ts # chat 子模块聚合入口
|
||||
│ │ │ │ ├─ controllers/ # 对外接口层(统一/指定平台 SSE 入口)
|
||||
│ │ │ │ ├─ application/ # 用例编排层(配额检查、路由、日志)
|
||||
│ │ │ │ ├─ domain/ # 领域规则层(会话/消息/策略)
|
||||
│ │ │ │ ├─ infrastructure/ # 基础设施层(Prisma/Redis/SSE/事件)
|
||||
│ │ │ │ ├─ dto/ # 请求/响应 DTO(仅用户端可见字段)
|
||||
│ │ │ │ └─ constants/ # chat 常量(事件类型、错误码、模型别名)
|
||||
│ │ │ ├─ sessions/ # 会话与历史查询(可逐步并入 chat)
|
||||
│ │ │ └─ profile/ # 用户资料、偏好设置、个人配置
|
||||
│ │ ├─ admin-app/ # 管理端边界:面向运营/管理能力
|
||||
│ │ │ ├─ admin-app.module.ts # 管理端聚合模块(auth/users/platforms/stats)
|
||||
│ │ │ ├─ auth/ # 管理端认证:邮箱登录、RBAC、审计
|
||||
│ │ │ ├─ users/ # 用户管理:查询、禁用、角色与额度治理
|
||||
│ │ │ ├─ platforms/ # 平台管理:密钥、权重、模型映射、健康检查
|
||||
│ │ │ ├─ stats/ # 统计报表:请求量、token、成本、错误率
|
||||
│ │ │ └─ audits/ # 审计日志:关键管理操作留痕
|
||||
│ │ └─ shared-domain/ # 双端共享能力(无业务端特有语义)
|
||||
│ │ ├─ ai-gateway/
|
||||
│ │ │ ├─ providers/ # 第三方平台适配实现(qwen/volc/deepseek)
|
||||
│ │ │ │ ├─ provider.interface.ts# provider 抽象协议,统一调用方式
|
||||
│ │ │ │ ├─ qwen.provider.ts
|
||||
│ │ │ │ ├─ volc.provider.ts
|
||||
│ │ │ │ └─ deepseek.provider.ts
|
||||
│ │ │ ├─ router/
|
||||
│ │ │ │ └─ provider-router.service.ts # 自动路由与降级策略
|
||||
│ │ │ └─ formatter/
|
||||
│ │ │ └─ stream-normalizer.service.ts # 统一 SSE chunk 输出协议
|
||||
│ │ ├─ identity/ # 身份能力:JWT 签发、策略、guard、token 工具
|
||||
│ │ ├─ sms/ # 短信能力:验证码发送、频控、模板封装
|
||||
│ │ ├─ mail/ # 邮件能力:登录通知、告警通知、模板发送
|
||||
│ │ └─ stats-core/ # 统计核心:聚合计算、指标定义、通用查询
|
||||
│ ├─ prisma/
|
||||
│ │ ├─ prisma.module.ts # Prisma 注入模块
|
||||
│ │ └─ prisma.service.ts # PrismaClient 生命周期与扩展
|
||||
│ └─ types/ # 全局类型声明(枚举、共享接口)
|
||||
├─ prisma/
|
||||
│ ├─ schema.prisma # 数据模型定义
|
||||
│ └─ migrations/ # 数据库迁移历史
|
||||
├─ docs/
|
||||
│ └─ project-solution.md # 架构与实现方案文档
|
||||
├─ .env.example # 环境变量示例
|
||||
├─ package.json # 依赖与脚本
|
||||
└─ tsconfig.json # TypeScript 编译配置
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 模块职责
|
||||
|
||||
### 3.1 用户端(`client-app`)
|
||||
|
||||
- **client-auth**
|
||||
- 仅负责短信验证码发送/校验、客户端 token 签发与刷新
|
||||
- **chat**
|
||||
- 提供统一 chat 接口与指定平台 chat 接口
|
||||
- 对外只暴露用户侧可见字段,不暴露平台敏感信息
|
||||
- 按 `controller -> application -> domain -> infrastructure` 分层,便于平滑拆分
|
||||
- **sessions/profile(可选)**
|
||||
- 会话记录、消息历史、个人资料
|
||||
|
||||
#### chat 子目录建议(简化版)
|
||||
|
||||
- **controllers**
|
||||
- 仅处理 HTTP/SSE 协议、参数校验、响应头,不写业务逻辑
|
||||
- **application**
|
||||
- 编排用例流程(鉴权通过后,做配额检查、路由 provider、写 usage)
|
||||
- **domain**
|
||||
- 放会话、消息、配额策略等核心业务规则与仓储抽象接口
|
||||
- **infrastructure**
|
||||
- 对接 Prisma、Redis、SSE writer、消息队列等外部依赖实现
|
||||
- **dto**
|
||||
- 负责 API 入参与出参定义,避免直接暴露内部模型
|
||||
- **constants**
|
||||
- 统一维护 chat 错误码、模型别名、事件类型常量
|
||||
|
||||
建议保持这个粒度即可,后续按开发规模再向下细分,不必一开始拆到文件级别。
|
||||
|
||||
### 3.2 管理端(`admin-app`)
|
||||
|
||||
- **admin-auth**
|
||||
- 仅负责邮箱密码登录(可选二次验证码)
|
||||
- **users**
|
||||
- 用户管理、封禁/解禁、角色治理
|
||||
- **platforms**
|
||||
- AI 平台开关、密钥、权重、模型映射、健康检查
|
||||
- **stats/audits**
|
||||
- 用量统计、成本分析、审计日志
|
||||
|
||||
### 3.3 共享域(`shared-domain`)
|
||||
|
||||
- **ai-gateway**
|
||||
- 第三方平台适配、自动路由、流式格式统一
|
||||
- **identity**
|
||||
- JWT strategy、通用 guard、token 工具
|
||||
- **sms/mail/stats-core**
|
||||
- 可复用基础设施能力,避免双端重复实现
|
||||
|
||||
> 设计原则:控制器和应用服务严格按端隔离,后续拆分时优先迁移 `client-app` 或 `admin-app` 整个目录,shared 部分按需复制或抽公共包。
|
||||
|
||||
---
|
||||
|
||||
## 4. API 设计(示例)
|
||||
|
||||
统一前缀建议:
|
||||
- 客户端:`/api/client/v1`
|
||||
- 管理端:`/api/admin/v1`
|
||||
|
||||
为避免后期冲突,建议从现在开始执行以下规范:
|
||||
- DTO 分离:`client-app/dto` 与 `admin-app/dto` 禁止互相引用;
|
||||
- Guard 分离:`ClientJwtGuard` 与 `AdminJwtGuard` 不混用;
|
||||
- Swagger 分离:客户端文档与管理端文档分组输出(如 `/docs-client`、`/docs-admin`);
|
||||
- 错误码分离:客户端错误码与管理端错误码使用不同前缀(如 `C_` / `A_`)。
|
||||
|
||||
### 4.1 客户端认证接口(短信)
|
||||
|
||||
- `POST /api/client/v1/auth/sms/send`
|
||||
- 入参:`{ phone, scene }`
|
||||
- 出参:`{ requestId, expireIn }`
|
||||
|
||||
- `POST /api/client/v1/auth/sms/login`
|
||||
- 入参:`{ phone, code }`
|
||||
- 出参:`{ accessToken, refreshToken, user }`
|
||||
|
||||
- `POST /api/client/v1/auth/refresh`
|
||||
- 入参:`{ refreshToken }`
|
||||
- 出参:`{ accessToken, refreshToken }`
|
||||
|
||||
### 4.2 客户端 AI Chat 接口(流式)
|
||||
|
||||
- `POST /api/client/v1/chat/completions/stream`
|
||||
- 说明:统一接口,后台自动路由平台
|
||||
- 入参示例:
|
||||
```json
|
||||
{
|
||||
"model": "gpt-4o-mini-like",
|
||||
"messages": [
|
||||
{ "role": "system", "content": "你是助手" },
|
||||
{ "role": "user", "content": "介绍一下NestJS" }
|
||||
],
|
||||
"temperature": 0.7,
|
||||
"platform": "auto"
|
||||
}
|
||||
```
|
||||
- 返回:`text/event-stream`(SSE)
|
||||
|
||||
- `POST /api/client/v1/chat/completions/stream/:platform`
|
||||
- 说明:指定平台(`qwen | volc | deepseek`)
|
||||
- 其余参数同上
|
||||
|
||||
### 4.3 建议统一 SSE 事件格式
|
||||
|
||||
```text
|
||||
event: meta
|
||||
data: {"requestId":"xxx","platform":"qwen","model":"qwen-turbo"}
|
||||
|
||||
event: delta
|
||||
data: {"content":"你好"}
|
||||
|
||||
event: usage
|
||||
data: {"promptTokens":120,"completionTokens":80,"totalTokens":200}
|
||||
|
||||
event: done
|
||||
data: {"finishReason":"stop"}
|
||||
|
||||
event: error
|
||||
data: {"code":"PLATFORM_TIMEOUT","message":"upstream timeout"}
|
||||
```
|
||||
|
||||
### 4.4 管理端认证接口(邮箱)
|
||||
|
||||
- `POST /api/admin/v1/auth/login`
|
||||
- 入参:`{ email, password }`
|
||||
- 出参:`{ accessToken, refreshToken, admin }`
|
||||
|
||||
- `POST /api/admin/v1/auth/refresh`
|
||||
- `POST /api/admin/v1/auth/logout`
|
||||
|
||||
### 4.5 管理端用户管理
|
||||
|
||||
- `GET /api/admin/v1/users`
|
||||
- `GET /api/admin/v1/users/:id`
|
||||
- `PATCH /api/admin/v1/users/:id/status`(启用/禁用)
|
||||
- `PATCH /api/admin/v1/users/:id/role`
|
||||
|
||||
### 4.6 管理端平台管理
|
||||
|
||||
- `GET /api/admin/v1/platforms`
|
||||
- `POST /api/admin/v1/platforms`
|
||||
- `PATCH /api/admin/v1/platforms/:id`
|
||||
- `PATCH /api/admin/v1/platforms/:id/health-check`
|
||||
|
||||
### 4.7 管理端统计
|
||||
|
||||
- `GET /api/admin/v1/stats/overview?startDate=&endDate=`
|
||||
- `GET /api/admin/v1/stats/platforms`
|
||||
- `GET /api/admin/v1/stats/users/top`
|
||||
|
||||
---
|
||||
|
||||
## 5. 自动路由与统一格式方案
|
||||
|
||||
### 5.1 自动路由策略(简版)
|
||||
|
||||
按优先级执行:
|
||||
1. 过滤禁用平台;
|
||||
2. 过滤健康检查失败平台;
|
||||
3. 根据模型支持能力过滤;
|
||||
4. 根据权重 + 当前错误率 + 当前限流剩余综合打分;
|
||||
5. 选择得分最高平台;
|
||||
6. 失败时自动降级重试下一个平台(最多 1~2 次)。
|
||||
|
||||
### 5.2 统一消息格式(内部 DTO)
|
||||
|
||||
- `ChatMessageDto`: `{ role, content, name?, toolCall? }`
|
||||
- `ChatRequestDto`: `{ model, messages, temperature, topP, stream, userId }`
|
||||
- `ChatChunkDto`: `{ type: 'meta'|'delta'|'usage'|'done'|'error', payload }`
|
||||
|
||||
第三方差异全部在 provider 内部适配,Controller 对外始终输出统一 SSE 事件。
|
||||
|
||||
---
|
||||
|
||||
## 6. 依赖清单(核心)
|
||||
|
||||
```bash
|
||||
# Nest 基础
|
||||
npm i @nestjs/common @nestjs/core @nestjs/platform-fastify @nestjs/config @nestjs/jwt @nestjs/passport @nestjs/swagger
|
||||
npm i class-validator class-transformer passport passport-jwt
|
||||
|
||||
# 数据库/缓存
|
||||
npm i @prisma/client ioredis
|
||||
npm i -D prisma
|
||||
|
||||
# 日志/安全/限流
|
||||
npm i nestjs-pino pino-http helmet @nestjs/throttler
|
||||
|
||||
# 任务/工具
|
||||
npm i @nestjs/schedule dayjs
|
||||
|
||||
# 第三方请求
|
||||
npm i undici
|
||||
|
||||
# 开发依赖
|
||||
npm i -D typescript ts-node tsx @types/node eslint prettier
|
||||
```
|
||||
|
||||
可选增强:
|
||||
- `argon2`:密码哈希
|
||||
- `zod`:配置或响应结构额外校验
|
||||
- `@opentelemetry/api`:链路追踪
|
||||
|
||||
---
|
||||
|
||||
## 7. 配置文件示例
|
||||
|
||||
### 7.1 `.env.example`
|
||||
|
||||
```env
|
||||
# App
|
||||
NODE_ENV=development
|
||||
PORT=3000
|
||||
APP_NAME=chat-one-service
|
||||
APP_BASE_URL=http://localhost:3000
|
||||
|
||||
# JWT
|
||||
JWT_ACCESS_SECRET=replace_me_access
|
||||
JWT_REFRESH_SECRET=replace_me_refresh
|
||||
JWT_ACCESS_EXPIRES_IN=2h
|
||||
JWT_REFRESH_EXPIRES_IN=30d
|
||||
|
||||
# PostgreSQL
|
||||
DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:5432/chat_one?schema=public
|
||||
|
||||
# Redis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=
|
||||
REDIS_DB=0
|
||||
|
||||
# SMS
|
||||
SMS_PROVIDER=aliyun
|
||||
SMS_ACCESS_KEY_ID=your_key
|
||||
SMS_ACCESS_KEY_SECRET=your_secret
|
||||
SMS_SIGN_NAME=ChatOne
|
||||
SMS_TEMPLATE_CODE_LOGIN=SMS_123456789
|
||||
SMS_CODE_TTL_SECONDS=300
|
||||
|
||||
# Mail (admin login / notice)
|
||||
MAIL_HOST=smtp.qq.com
|
||||
MAIL_PORT=465
|
||||
MAIL_SECURE=true
|
||||
MAIL_USER=xxx@qq.com
|
||||
MAIL_PASS=app_password
|
||||
MAIL_FROM=ChatOne <xxx@qq.com>
|
||||
|
||||
# AI Providers
|
||||
QWEN_API_KEY=your_qwen_key
|
||||
QWEN_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
|
||||
VOLC_API_KEY=your_volc_key
|
||||
VOLC_BASE_URL=https://ark.cn-beijing.volces.com/api/v3
|
||||
DEEPSEEK_API_KEY=your_deepseek_key
|
||||
DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
|
||||
|
||||
# Route Strategy
|
||||
AI_ROUTE_RETRY_TIMES=1
|
||||
AI_ROUTE_TIMEOUT_MS=45000
|
||||
|
||||
# Split-ready(拆分预留)
|
||||
CLIENT_PORT=3000
|
||||
ADMIN_PORT=3001
|
||||
CLIENT_JWT_ACCESS_SECRET=replace_me_client_access
|
||||
ADMIN_JWT_ACCESS_SECRET=replace_me_admin_access
|
||||
REDIS_KEY_PREFIX_CLIENT=chatone:client
|
||||
REDIS_KEY_PREFIX_ADMIN=chatone:admin
|
||||
```
|
||||
|
||||
### 7.2 `src/config/validation.ts`(建议)
|
||||
|
||||
使用 `class-validator` 或 `zod` 校验环境变量,应用启动即失败(fail fast),避免线上缺配置。
|
||||
|
||||
---
|
||||
|
||||
## 8. 数据库设计(PostgreSQL)
|
||||
|
||||
以下为简化且够用的核心表:
|
||||
|
||||
### 8.1 用户与管理员
|
||||
|
||||
- `users`
|
||||
- `id` (bigserial pk)
|
||||
- `phone` (varchar unique)
|
||||
- `nickname` (varchar)
|
||||
- `status` (smallint, 1正常 0禁用)
|
||||
- `created_at`, `updated_at`
|
||||
|
||||
- `admins`
|
||||
- `id`
|
||||
- `email` (varchar unique)
|
||||
- `password_hash` (varchar)
|
||||
- `role` (varchar: super_admin/admin/ops)
|
||||
- `status`
|
||||
- `last_login_at`
|
||||
- `created_at`, `updated_at`
|
||||
|
||||
### 8.2 平台配置与模型映射
|
||||
|
||||
- `ai_platforms`
|
||||
- `id`
|
||||
- `code` (varchar unique: qwen/volc/deepseek)
|
||||
- `name`
|
||||
- `enabled` (bool)
|
||||
- `weight` (int default 100)
|
||||
- `priority` (int default 100)
|
||||
- `base_url`
|
||||
- `api_key_encrypted`
|
||||
- `timeout_ms`
|
||||
- `rpm_limit`
|
||||
- `health_status` (varchar: healthy/unhealthy/unknown)
|
||||
- `created_at`, `updated_at`
|
||||
|
||||
- `ai_platform_models`
|
||||
- `id`
|
||||
- `platform_id` (fk)
|
||||
- `biz_model` (varchar) # 业务统一模型名
|
||||
- `provider_model` (varchar) # 平台真实模型名
|
||||
- `enabled` (bool)
|
||||
- unique(platform_id, biz_model)
|
||||
|
||||
### 8.3 会话与消息(可选落库)
|
||||
|
||||
- `chat_sessions`
|
||||
- `id`
|
||||
- `user_id` (fk)
|
||||
- `title`
|
||||
- `created_at`, `updated_at`
|
||||
|
||||
- `chat_messages`
|
||||
- `id`
|
||||
- `session_id` (fk)
|
||||
- `role` (user/assistant/system)
|
||||
- `content` (text)
|
||||
- `token_count` (int)
|
||||
- `provider` (varchar)
|
||||
- `created_at`
|
||||
|
||||
### 8.4 请求审计与统计
|
||||
|
||||
- `ai_request_logs`
|
||||
- `id`
|
||||
- `request_id` (varchar unique)
|
||||
- `user_id` (fk nullable)
|
||||
- `platform_code`
|
||||
- `biz_model`
|
||||
- `provider_model`
|
||||
- `status` (success/fail)
|
||||
- `error_code`
|
||||
- `latency_ms`
|
||||
- `prompt_tokens`
|
||||
- `completion_tokens`
|
||||
- `total_tokens`
|
||||
- `estimated_cost`
|
||||
- `created_at`
|
||||
|
||||
- `usage_daily_stats`
|
||||
- `id`
|
||||
- `stat_date` (date)
|
||||
- `dimension` (platform/user/total)
|
||||
- `dimension_key` (varchar)
|
||||
- `request_count`
|
||||
- `success_count`
|
||||
- `fail_count`
|
||||
- `total_tokens`
|
||||
- `estimated_cost`
|
||||
- unique(stat_date, dimension, dimension_key)
|
||||
|
||||
---
|
||||
|
||||
## 9. 缓存方案(Redis)
|
||||
|
||||
建议键设计:
|
||||
|
||||
- 短信验证码:`sms:code:{phone}:{scene}`(TTL 5 分钟)
|
||||
- 短信发送频控:`sms:send:limit:{phone}`(TTL 60 秒)
|
||||
- 刷新令牌黑名单:`auth:rt:blacklist:{jti}`(TTL 到 token 过期)
|
||||
- 用户会话缓存:`auth:user:{userId}`(TTL 30 分钟,可选)
|
||||
- 平台健康状态:`ai:platform:health:{code}`(TTL 30 秒)
|
||||
- 平台动态权重:`ai:platform:weight:{code}`(TTL 60 秒)
|
||||
- 统计临时聚合:`stats:daily:{date}:{dimension}`(TTL 1 天)
|
||||
|
||||
为便于拆分,建议从第一天就加命名空间前缀:
|
||||
- 用户端:`chatone:client:*`
|
||||
- 管理端:`chatone:admin:*`
|
||||
- 共享:`chatone:shared:*`
|
||||
|
||||
同时启用 `@nestjs/throttler` 做接口限流:
|
||||
- 客户端 chat 接口:按用户 + IP 双维度限流;
|
||||
- 登录接口:按手机号/邮箱严格限流,防刷。
|
||||
|
||||
---
|
||||
|
||||
## 10. 登录与鉴权方案
|
||||
|
||||
### 10.1 客户端(短信登录)
|
||||
|
||||
1. 用户请求发送验证码;
|
||||
2. 服务端生成验证码写入 Redis(哈希存储,避免明文);
|
||||
3. 用户提交验证码登录,校验通过后签发 JWT;
|
||||
4. AccessToken 短期(2h),RefreshToken 长期(30d);
|
||||
5. 刷新时校验 RefreshToken 的 `jti` 与黑名单状态;
|
||||
6. 注销时将 RefreshToken `jti` 拉黑至过期。
|
||||
|
||||
### 10.2 管理端(邮箱登录)
|
||||
|
||||
1. 邮箱 + 密码登录(密码 `argon2` 哈希);
|
||||
2. 可选开启邮箱二次验证码;
|
||||
3. JWT + RBAC(`super_admin` / `admin` / `ops`);
|
||||
4. 管理端接口统一加 `JwtAuthGuard + RolesGuard`;
|
||||
5. 关键操作(平台密钥修改、用户封禁)记录审计日志。
|
||||
|
||||
### 10.3 Token 建议
|
||||
|
||||
- AccessToken:只放必要字段(`sub`, `role`, `type`)
|
||||
- RefreshToken:包含 `jti`,便于撤销
|
||||
- 密钥轮转:支持双密钥平滑切换(`kid`)
|
||||
- 传输:优先 `Authorization: Bearer`;管理端也可改 HttpOnly Cookie
|
||||
- 强隔离建议:客户端与管理端使用不同 `issuer`、`audience`、`secret`,token 绝不互认
|
||||
|
||||
---
|
||||
|
||||
## 11. 拆分演进路线(低成本)
|
||||
|
||||
### 阶段 A:单体双端(当前推荐)
|
||||
- 一个 Nest 进程,两个 AppModule(`client-app` / `admin-app`);
|
||||
- 共用数据库与 Redis,但 key 前缀、token 体系已隔离;
|
||||
- 发布快,开发成本最低。
|
||||
|
||||
### 阶段 B:双进程同仓
|
||||
- 启动两个入口:`main.client.ts`、`main.admin.ts`;
|
||||
- 用户端和管理端可独立扩容、独立发布;
|
||||
- 共享逻辑仍来自 `shared-domain`。
|
||||
|
||||
### 阶段 C:双服务拆仓(可选)
|
||||
- `client-service`:保留短信、chat、会话;
|
||||
- `admin-service`:保留邮箱登录、平台管理、统计审计;
|
||||
- `shared-domain` 抽为内部 npm 包或 Git 子模块。
|
||||
|
||||
---
|
||||
|
||||
## 12. 最小可用开发流程(MVP)
|
||||
|
||||
建议按下面顺序实现,2~3 周可交付可用版本:
|
||||
|
||||
1. 初始化 NestJS + Prisma + PostgreSQL + Redis;
|
||||
2. 完成客户端短信登录与 JWT 刷新;
|
||||
3. 完成 Qwen 单平台流式 chat;
|
||||
4. 抽象 provider 接口,接入 Volc、DeepSeek;
|
||||
5. 实现统一流式格式 + 自动路由;
|
||||
6. 完成管理端邮箱登录;
|
||||
7. 完成平台管理、用户管理;
|
||||
8. 完成请求日志与基础统计报表;
|
||||
9. 完成 Swagger、限流、异常处理与日志。
|
||||
|
||||
---
|
||||
|
||||
## 13. 非功能建议(上线前)
|
||||
|
||||
- **安全**:API Key 加密存储;生产环境开启 Helmet/CORS 白名单;
|
||||
- **稳定性**:上游超时、熔断、重试与降级;
|
||||
- **可观测性**:请求链路 ID、结构化日志、错误告警;
|
||||
- **成本控制**:平台权重 + 单用户日额度 + 模型白名单;
|
||||
- **测试**:核心流程至少有 e2e(登录、chat、管理端鉴权)。
|
||||
|
||||
---
|
||||
|
||||
## 14. 一句话总结
|
||||
|
||||
该方案以 NestJS + Prisma + PostgreSQL + Redis 为核心,采用“**用户端/管理端强隔离 + shared-domain 复用**”组织代码,在保持开发效率的同时确保后续可平滑拆分为两个独立服务,并持续支持多平台 AI 路由与统一流式协议。
|
||||
Reference in New Issue
Block a user