feat(error): 业务错误码注册表(子模块 + openspec change + guide)
Some checks are pending
CI / backend (push) Waiting to run
CI / frontend (push) Waiting to run

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
liuyun 2026-10-11 22:42:18 +08:00
parent ed9af5337d
commit 062b314844
7 changed files with 99 additions and 2 deletions

View File

@ -473,7 +473,7 @@ useDict(code) // → { items, tagMap, options },均响应式
{ "code": 0, "message": "ok", "data": { } } { "code": 0, "message": "ok", "data": { } }
``` ```
- `code=0` 成功;失败 `code = HTTP状态码 * 100`(401→40100,403→40300,400→40000,500→50000)。 - `code=0` 成功;失败 `code` 为业务码(5 位 `[域码 2 位][序 3 位]`,单一注册表见 [`src/common/error-codes.ts`](../sources/sysmgr-nest/src/common/error-codes.ts),如 `10001` 账号或密码错误、`11002` 用户名已存在);未登记业务码的异常回退 `HTTP状态码 × 100`(40000/40100/40300/40400/40900/50000)。
- 前端 `http` 已自动拆包:成功拿 `data`,失败抛 `ApiError(code, message)`。 - 前端 `http` 已自动拆包:成功拿 `data`,失败抛 `ApiError(code, message)`。
### 4.2 分页 ### 4.2 分页

View File

@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-10-11

View File

@ -0,0 +1,40 @@
## Context
`AllExceptionsFilter` 目前把 `HttpException` 统一映射为 `code = HTTP 状态 ×100`;业务 throw 都是 `BadRequestException/ConflictException/NotFoundException('字符串')`,无 code。前端 `ApiError(code, message)` 已读 code,但无稳定业务码可分支。动机见 proposal.md - Why。
## Goals / Non-Goals
**Goals:**
- 建立单一错误码注册表与 `BusinessException`,迁移关键业务错误。
**Non-Goals:**
- 不一次性迁移全部 throw(逐步);不引入错误码国际化/多语言。
## Decisions
### D1 — code 方案:`[域码 2 位][序 3 位]`
5 位数字。域码固定:00 通用、10 认证、11 用户、12 角色、13 资源、14 组织、15 租户、16 字典、17 配置、18 审计、19 登录、20 会话、21 通知。HTTP 状态由 `BusinessException` 单独携带,`code` 与 HTTP 解耦。
### D2 — `BusinessException` + 过滤器识别
`src/common/business-exception.ts`:`class BusinessException extends HttpException { constructor(code, message, status = 400) }`。`AllExceptionsFilter`:若为 `BusinessException` 用其 `code`,否则回退 `status×100`。
### D3 — 注册表为单一事实源
`src/common/error-codes.ts` 集中登记:通用码 + 各域码,注释标明 HTTP 状态。新增业务错误先在注册表加码,再 `throw new BusinessException(ErrorCodes.XXX, '...')`。
### D4 — 迁移关键错误(示例集)
迁移:登录(账号或密码错误/锁定/停用)、待改密门禁、用户名冲突、原密码错误、用户/租户/资源不存在、越权等高频错误;其余保留字符串(可后续迁移)。
## Risks / Trade-offs
- **[code 与 HTTP 解耦后前端需注意]** → 前端 `ApiError.code` 现为业务码;HTTP 状态仍用于 401 自动刷新(http.ts 按 status 判断,不受影响)。
- **[迁移不完整]** → 未迁移的仍回退 `status×100`,与注册码并存,逐步收敛。
## Migration Plan
无数据迁移;纯后端代码 + 文档。回滚即撤销。
## Open Questions
无。

View File

@ -0,0 +1,21 @@
## Why
当前业务错误都是字符串消息(`throw new BadRequestException('用户名已存在')`),无统一错误码,前端无法按 code 分支处理,fork 后各模块各自为政。需要一套「业务域 + 错误序」的错误码注册表作为单一事实源。
## What Changes
- 新增 `src/common/error-codes.ts` 错误码注册表(5 位数字 `[域码 2 位][序 3 位]`,域码集中登记)。
- 新增 `BusinessException(code, message, status)`;`AllExceptionsFilter` 识别业务码,非业务异常仍回退 `HTTP×100`。
- 迁移关键业务错误(登录/锁定/待改密/用户名冲突/租户不存在等)到注册码。
## Capabilities
### Modified Capabilities
- `shared/api-contract`: 「错误码分段」改为「业务域 + 错误序」细分段。
## Impact
- **后端**:`error-codes.ts` + `business-exception.ts`(common)、`AllExceptionsFilter` 识别业务码、auth/users/tenants 等关键 throw 迁移。
- **文档**:guide.md 补错误码注册表说明。
- 无数据/前端变更(前端仍读 `code` + `message`)。

View File

@ -0,0 +1,16 @@
## MODIFIED Requirements
### Requirement: 错误码分段
错误码 SHALL 采用「业务域 + 错误序」分段:5 位数字 `[域码 2 位][序 3 位]`,域码集中登记于 `error-codes` 注册表(00 通用、10 认证、11 用户、12 角色、13 资源、14 组织、15 租户、16 字典、17 配置、20 会话、21 通知…);HTTP 状态仍按语义返回(400/401/403/404/409/500),`code` 为业务码。
#### Scenario: 未登录
- **WHEN** 未携带有效 token 访问受保护接口
- **THEN** HTTP 401,code 为认证域业务码(如 10002),无业务码时回退 40100
#### Scenario: 业务错误码
- **WHEN** 业务处理失败(如用户名已存在)
- **THEN** 返回对应 HTTP 状态 + 注册表内的业务码与可读 message
#### Scenario: 系统错误兜底
- **WHEN** 非业务异常(框架/未知错误)
- **THEN** code 回退为 HTTP 状态 ×100

View File

@ -0,0 +1,18 @@
## 1. 基础设施
- [x] 1.1 新增 `src/common/error-codes.ts`(域码 + 通用码 + 各域码集中登记)
- [x] 1.2 新增 `src/common/business-exception.ts`(`BusinessException(code, message, status)`)
- [x] 1.3 `AllExceptionsFilter` 识别 `BusinessException`,否则回退 `status×100`
## 2. 迁移关键错误
- [x] 2.1 `auth.service`:登录失败/锁定/停用/待改密/原密码错误
- [x] 2.2 `users.service`:用户名冲突、用户不存在
- [x] 2.3 `tenants.service`:租户不存在/已存在
- [x] 2.4 `sessions.service`:会话不存在
## 3. 文档与验证
- [x] 3.1 guide.md 补错误码注册表说明
- [x] 3.2 后端 build + 单测 + e2e 通过
- [x] 3.3 冒烟:触发一个业务错误,返回注册业务码而非 status×100

@ -1 +1 @@
Subproject commit f747ad5442e314f41d9319b61941da5f7af69096 Subproject commit 8eefa7fa4499ed9b3c733211794360fad26061b4