
## MODIFIED Requirements

### Requirement: 参数校验错误不泄露内部细节

系统在处理参数校验失败时 SHALL 避免向客户端泄露校验细节（字段名、规则表达式等），以减少对外暴露内部实现并保持错误语义稳定。

#### Scenario: validator 校验失败的对外返回

- **WHEN** Handler 使用 validator 对请求参数进行校验且校验失败
- **THEN** Handler 对外仅返回 `errors.New(errors.CodeInvalidParam)`
- **AND** 响应的 `msg` 为统一短消息（例如“参数验证失败”）
- **AND** 不拼接或直接返回 `validator` 的 `err.Error()`

#### Scenario: 校验细节仅写入日志

- **WHEN** 参数校验失败
- **THEN** 系统在日志中记录完整的校验错误细节（用于排查）
- **AND** 日志字段包含请求路径、请求方法、request_id（如可用）

## ADDED Requirements

### Requirement: Service 对外错误必须结构化

Service 层 SHALL 对外返回结构化错误（AppError），以确保全局 ErrorHandler 能正确区分 4xx 业务错误与 5xx 系统错误。

#### Scenario: 预期业务错误返回 4xx

- **WHEN** Service 发生可预期的业务错误（例如：验证码错误/过期、状态不允许、资源不存在）
- **THEN** 返回 `errors.New(<4xx-code>[, message])`
- **AND** 全局 ErrorHandler 将其映射为对应的 4xx HTTP 状态码

#### Scenario: 非预期系统错误返回 5xx

- **WHEN** Service 调用数据库/缓存/队列/第三方依赖发生错误
- **THEN** 返回 `errors.Wrap(<5xx-code>, err, "业务动作失败")`
- **AND** 客户端响应 `msg` 为错误码映射表中的通用描述（不包含底层 err 细节）

#### Scenario: 禁止 fmt.Errorf 作为对外错误

- **WHEN** Service 需要对外返回错误
- **THEN** 不使用 `fmt.Errorf(...)` 作为返回值
- **AND** 必须转换为 `errors.New(...)` 或 `errors.Wrap(...)`
