From cfb165148017207bdac8213714d0c82a2548d3b6 Mon Sep 17 00:00:00 2001 From: bujinyuan Date: Mon, 2 Mar 2026 14:12:06 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=96=B0=E5=A2=9E=E5=89=8D=E5=90=8E?= =?UTF-8?q?=E7=AB=AF=E9=9B=86=E6=88=90=E5=BC=80=E5=8F=91=E8=A7=84=E8=8C=83?= =?UTF-8?q?=EF=BC=8C=E6=9B=B4=E6=96=B0=E9=A1=B9=E7=9B=AE=E8=A7=84=E5=88=99?= =?UTF-8?q?=E4=B8=8E=E8=BF=9B=E5=BA=A6=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 创建 docs/conventions/frontend-backend-integration.md 完整规范:API响应格式、HTTP状态码语义、前端错误处理、后端错误处理、 前后端错误码对照表、安全约束、检查清单 - 更新 .cursor/rules/project-context.mdc 加入前后端联动规范6条 - 更新 CURRENT_STATUS.md 记录修复内容和规范引用 Made-with: Cursor --- .cursor/rules/project-context.mdc | 59 +++++ .../frontend-backend-integration.md | 204 ++++++++++++++++++ docs/progress/CURRENT_STATUS.md | 15 +- 3 files changed, 273 insertions(+), 5 deletions(-) create mode 100644 .cursor/rules/project-context.mdc create mode 100644 docs/conventions/frontend-backend-integration.md diff --git a/.cursor/rules/project-context.mdc b/.cursor/rules/project-context.mdc new file mode 100644 index 0000000..77d7c54 --- /dev/null +++ b/.cursor/rules/project-context.mdc @@ -0,0 +1,59 @@ +--- +description: EchoChat 项目上下文与开发记忆 - 每次新对话自动加载 +alwaysApply: true +--- + +# EchoChat 项目上下文 + +## 快速恢复上下文 + +**新对话开始时,必须先读取以下文件恢复项目记忆:** + +1. `docs/progress/CURRENT_STATUS.md` — 项目开发进度、已完成 Task、关键技术决策、下一步工作 +2. 当前阶段的实施计划文档(位于 `docs/plans/` 目录下) + +## 当前进度 + +- **Phase 1(基础设施与用户认证)**:✅ 全部完成(11 个 Task) +- **Phase 2(即时通讯)**:待制定实施计划 +- 分支:`feature/phase1-foundation-and-auth`(待合并到 main) + +## 项目概述 + +EchoChat 是一个实时音视频通讯平台,包含三个子项目: +- `backend/go-service/` — Go 后端(Gin + GORM + Wire + Redis) +- `frontend/` — 前台用户端(uni-app + Vue 3.4 + Pinia 2.x) +- `admin/` — 后台管理端(Vue 3.5+ + Element Plus + Pinia 3.x) + +## 核心开发规则 + +1. **前端设计**:必须使用 `ui-ux-pro-max` 技能包(`~/.agent/skills/ui-ux-pro-max/scripts/search.py`),禁止手动设计 +2. **工作流**:使用 superpowers 流程控制开发节奏 +3. **两端差异**:`frontend/` 和 `admin/` 是完全独立的项目,技术栈不需要统一 +4. **模块系统**:前端统一使用 ESM(`export`/`import`),禁止 CommonJS +5. **Go 常量命名**:camelCase(`UserStatusActive`),非大写下划线 +6. **API 响应**:统一 `{ "code": 0, "message": "success", "data": ... }` +7. **JWT 策略**:有状态 JWT,Token 存 Redis,登出时从 Redis 删除 +8. **代码注释**:所有公开函数、组件、Store 必须有详细注释 +9. **文档同步**:代码变更后必须同步更新 docs/ 下相关文档 +10. **验证方式**:使用 Playwright MCP 进行页面自动化验证 +11. **代码审查**:每个 Task 完成后,使用 `code-reviewer` 子代理进行结构化审查,确保代码质量和计划一致性 +12. **完成验证**:使用 `verification-before-completion` 技能,在声称完成前运行验证命令并确认输出 + +## 前后端联动规范(必须遵守) + +> 详细规范见 `docs/conventions/frontend-backend-integration.md` + +1. **错误提示统一**:前端所有 HTTP 错误提示必须优先使用后端 `data.message`,禁止硬编码覆盖后端信息。Fallback 文案仅在后端无响应体时使用 +2. **HTTP 状态码语义**:后端必须返回正确的 HTTP 状态码(200/400/401/403/404/500),前端按状态码分类处理 +3. **安全防护**:后端登录接口对"用户不存在"与"密码错误"统一返回 401 + "账号或密码错误",禁止通过不同错误码泄露用户是否存在 +4. **401 场景区分**:前端拦截器区分「登录/注册请求的 401」(仅提示错误)和「已认证请求的 401」(清 Token + 跳转登录页) +5. **响应格式一致**:后端所有响应必须使用 `utils.Response*` 系列函数,保证统一的 `{ code, message, data, trace_id, time }` 结构 +6. **业务错误映射**:后端 Controller 的 `handleError` 函数必须覆盖所有已知业务错误,不能忽略 error(`_`) + +## 设计系统 + +持久化在 `design-system/echochat/` 目录: +- `MASTER.md` — 全局设计规范 +- `pages/*.md` — 页面级覆盖规则 +- 色板:Primary `#2563EB` / BG `#F8FAFC` / Text `#1E293B` diff --git a/docs/conventions/frontend-backend-integration.md b/docs/conventions/frontend-backend-integration.md new file mode 100644 index 0000000..6303a1b --- /dev/null +++ b/docs/conventions/frontend-backend-integration.md @@ -0,0 +1,204 @@ +# 前后端集成开发规范 + +> **适用范围**:EchoChat 项目全端(Go 后端 + admin 管理端 + frontend 用户端) +> **创建日期**:2026-03-02 +> **最后更新**:2026-03-02 + +--- + +## 一、API 响应格式规范 + +### 1.1 后端统一响应结构 + +所有后端 API 必须使用 `pkg/utils/response.go` 中的 `Response*` 系列函数返回响应,保证结构一致: + +```json +{ + "code": 0, + "message": "success", + "data": {}, + "trace_id": "uuid-v4", + "time": "2026-03-02 14:00:00" +} +``` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `code` | int | 业务状态码:0=成功,非 0=HTTP 状态码 | +| `message` | string | 人类可读的描述信息,**前端直接展示给用户** | +| `data` | any | 业务数据,失败时为 null | +| `trace_id` | string | 请求追踪 ID,用于日志排查 | +| `time` | string | 服务器响应时间 | + +### 1.2 后端 Response 函数对照 + +| 函数 | HTTP Status | code | 使用场景 | +|------|-------------|------|----------| +| `ResponseOK` | 200 | 0 | 请求成功 | +| `ResponseCreated` | 201 | 0 | 资源创建成功 | +| `ResponseBadRequest` | 400 | 400 | 参数错误、业务规则校验失败 | +| `ResponseUnauthorized` | 401 | 401 | 认证失败(密码错误、Token 无效/过期) | +| `ResponseForbidden` | 403 | 403 | 权限不足、账号被禁用 | +| `ResponseNotFound` | 404 | 404 | 资源不存在 | +| `ResponseError` | 500 | 500 | 服务器内部错误 | + +### 1.3 message 字段要求 + +- **必须是中文**,面向最终用户 +- **必须精准描述错误原因**,不能笼统(如 "操作失败") +- **安全场景除外**:登录时"用户不存在"和"密码错误"统一为 "账号或密码错误" + +--- + +## 二、HTTP 状态码使用规范 + +### 2.1 状态码语义 + +| 状态码 | 语义 | 后端使用场景 | +|--------|------|-------------| +| 200 | OK | 查询成功、操作成功 | +| 201 | Created | 资源创建成功(注册、新建用户) | +| 400 | Bad Request | 参数校验失败、业务规则不满足 | +| 401 | Unauthorized | 认证失败:密码错误、Token 过期/无效/已注销 | +| 403 | Forbidden | 权限不足:角色不匹配、账号被禁用/注销 | +| 404 | Not Found | 请求的资源不存在 | +| 500 | Internal Server Error | 服务器内部错误 | + +### 2.2 安全约束 + +**登录接口的 401 响应**: + +``` +✅ 正确:用户不存在 → 401 "账号或密码错误" +✅ 正确:密码错误 → 401 "账号或密码错误" +❌ 错误:用户不存在 → 404 "用户不存在"(暴露用户是否注册) +``` + +防止用户枚举攻击,登录场景下所有认证失败统一返回相同状态码和信息。 + +--- + +## 三、前端错误处理规范 + +### 3.1 核心原则 + +1. **后端 message 优先**:所有 HTTP 错误提示必须优先使用 `data.message` +2. **禁止硬编码覆盖**:不能用前端硬编码的文案替换后端返回的错误信息 +3. **Fallback 仅兜底**:`|| '默认文案'` 仅在后端无响应体或无 message 字段时触发 +4. **按状态码分类处理**:不同 HTTP 状态码执行不同的副作用(跳转、清 Token 等) + +### 3.2 管理端(admin/)错误处理 + +文件:`admin/src/utils/request.js` + +``` +HTTP 响应成功(2xx): + ├─ code === 0 → 返回数据 + └─ code !== 0 → ElMessage.error(data.message || '请求失败') + +HTTP 响应错误: + ├─ 401 + │ ├─ 在登录页 → ElMessage.error(data.message || '登录已过期') + │ └─ 非登录页 → ElMessage.error(data.message || '登录已过期') + 清 Token + 跳转 /login + ├─ 403 → ElMessage.error(data.message || '没有访问权限') + ├─ 其他 → ElMessage.error(data.message || '请求错误(N)') + └─ 网络异常 → ElMessage.error('网络异常,请检查网络连接') +``` + +**401 场景区分的关键**:通过 `router.currentRoute.value.path === '/login'` 判断当前是否在登录页。登录页不清 Token 不跳转,仅显示错误。 + +### 3.3 前台用户端(frontend/)错误处理 + +文件:`frontend/src/utils/request.js` + +``` +HTTP 响应成功(2xx): + ├─ code === 0 → resolve(data) + └─ code !== 0 → showToast(data.message || '请求失败') + +HTTP 响应错误: + ├─ 401 + │ ├─ 登录/注册请求 → showToast(data.message || '登录已过期') + │ └─ 其他请求 → showToast(data.message || '登录已过期') + removeToken() + 跳转登录页 + ├─ 403 → showToast(data.message || '没有访问权限') + ├─ 其他 → showToast(data.message || '请求错误(N)') + └─ 网络异常 → showToast('网络异常,请检查网络连接') +``` + +**401 场景区分的关键**:通过正则 `/\/auth\/(login|register)$/` 匹配请求 URL。登录/注册请求不清 Token 不跳转。 + +### 3.4 错误处理检查清单 + +新增 API 接口时,必须确认以下各项: + +- [ ] 后端 Controller 使用正确的 `Response*` 函数 +- [ ] 后端 Controller 的 error switch 覆盖所有已知业务错误 +- [ ] 后端不使用 `_` 忽略 error,至少 log warning +- [ ] 前端调用方的 catch 不自行覆盖 message(交给拦截器统一处理) +- [ ] 前端页面级 catch 只做状态清理(如 loading = false),不重复弹提示 + +--- + +## 四、后端错误处理规范 + +### 4.1 Controller 层 + +- 使用 switch/case 或 if/else 匹配所有已知业务错误 +- 每种错误映射到正确的 HTTP 状态码 +- message 参数必须是用户友好的中文描述 +- default 分支处理未知错误,返回 500 + +```go +if err := svc.DoSomething(ctx, req); err != nil { + switch err { + case service.ErrNotFound: + utils.ResponseNotFound(c, "资源不存在") + case service.ErrInvalidParam: + utils.ResponseBadRequest(c, "参数无效") + default: + logs.Error(ctx, funcName, "操作失败", zap.Error(err)) + utils.ResponseError(c, "操作失败") + } + return +} +``` + +### 4.2 Service 层 + +- 定义明确的业务错误变量(`var ErrXxx = errors.New("...")`) +- 不在 Service 层直接返回 HTTP 状态码,由 Controller 映射 +- DAO 层的 `gorm.ErrRecordNotFound` 必须转换为业务错误 + +### 4.3 禁止忽略错误 + +```go +// ❌ 错误:忽略 error +roles, _ := s.roleDAO.GetUserRoleCodes(ctx, user.ID) + +// ✅ 正确:处理 error +roles, err := s.roleDAO.GetUserRoleCodes(ctx, user.ID) +if err != nil { + logs.Warn(ctx, funcName, "获取角色失败", zap.Error(err)) + roles = []string{} +} +``` + +--- + +## 五、前后端错误码对照表 + +| 后端场景 | HTTP | message 示例 | 前端行为 | +|---------|------|-------------|---------| +| 登录-密码错误 | 401 | 账号或密码错误 | 显示 message | +| 登录-用户不存在 | 401 | 账号或密码错误 | 显示 message | +| 登录-账号被禁用 | 403 | 账号已被禁用 | 显示 message | +| Token 过期 | 401 | 认证已过期或无效,请重新登录 | 显示 message + 清 Token + 跳转 | +| Token 已注销 | 401 | 认证已失效,请重新登录 | 显示 message + 清 Token + 跳转 | +| 缺少认证信息 | 401 | 缺少认证信息 | 显示 message + 清 Token + 跳转 | +| 权限不足 | 403 | 权限不足,需要角色: admin 或 super_admin | 显示 message | +| 参数校验失败 | 400 | 参数校验失败: ... | 显示 message | +| 用户名已注册 | 400 | 用户名或邮箱已被注册 | 显示 message | +| 不能禁用自己 | 400 | 不能禁用自己的账号 | 显示 message | +| 用户不存在 | 404 | 用户不存在 | 显示 message | +| 服务器内部错误 | 500 | 获取用户列表失败 | 显示 message | +| 网络异常 | - | (无响应体) | 显示前端 fallback 文案 | diff --git a/docs/progress/CURRENT_STATUS.md b/docs/progress/CURRENT_STATUS.md index d7bca2c..cda7cee 100644 --- a/docs/progress/CURRENT_STATUS.md +++ b/docs/progress/CURRENT_STATUS.md @@ -1,6 +1,6 @@ # EchoChat 项目开发进度 -> **最后更新**:2026-03-02(Phase 1 全部完成 — Task 11 完成后更新) +> **最后更新**:2026-03-02(前后端错误处理规范统一 + 安全加固) > **当前阶段**:Phase 1 - 基础设施与用户认证 > **当前分支**:`feature/phase1-foundation-and-auth` > **实施计划**:`docs/plans/2026-02-27-phase1-foundation-and-auth.md` @@ -95,6 +95,8 @@ EchoChat/ └── docs/ ├── api/ # API 接口文档 ├── architecture/ # 系统架构文档 + ├── conventions/ # 开发规范文档 + │ └── frontend-backend-integration.md # 前后端集成规范 ├── plans/ # 实施计划文档 └── progress/ # 进度文档(本文件) ``` @@ -111,6 +113,7 @@ EchoChat/ 6. **验证方式**:Playwright MCP 进行页面自动化验证 7. **代码审查**:每个 Task 完成后,使用 `code-reviewer` 子代理进行结构化代码审查,对照实施计划和编码标准检查 8. **完成验证**:使用 `verification-before-completion` 技能,在声称完成前必须运行验证命令并确认输出结果 +9. **前后端联动规范**:详见 `docs/conventions/frontend-backend-integration.md`,核心要求:前端错误提示必须优先使用后端 message,禁止硬编码覆盖;后端错误处理禁止忽略 error;登录安全统一返回 401 --- @@ -157,10 +160,12 @@ cd frontend && npm run dev:h5 ## 六、已知问题与注意事项 1. ~~前端工具模块使用了 CommonJS,已修复为 ESM~~(已解决) -2. uni-app 的 `tabBar.custom: true` 配合自定义 TabBar 组件使用 -3. 管理端和前台的 localStorage key 通过前缀隔离(`admin_` vs `echo_`) -4. Go 依赖版本需匹配 Go 1.23.12,不要随意升级 Go 工具链 -5. `.gitignore` 已配置忽略:`.cursor/`、`.vite/`、`node_modules/`、`dist/`、`*.png`(根目录截图)、`logs/` 等 +2. ~~前端登录失败时错误提示不正确(硬编码"登录已过期"覆盖后端消息)~~(已修复,详见 `docs/conventions/frontend-backend-integration.md`) +3. ~~后端登录时用户不存在返回 404 暴露用户是否注册~~(已修复为统一返回 401) +4. uni-app 的 `tabBar.custom: true` 配合自定义 TabBar 组件使用 +5. 管理端和前台的 localStorage key 通过前缀隔离(`admin_` vs `echo_`) +6. Go 依赖版本需匹配 Go 1.23.12,不要随意升级 Go 工具链 +7. `.gitignore` 已配置忽略:`.cursor/`、`.vite/`、`node_modules/`、`dist/`、`*.png`(根目录截图)、`logs/` 等 ---