refactor(error): profile 错误分类全面转 typed error,删除文案匹配

- module-runtime 新增 RuntimeProfileRewardCodeRedeemErrorCode(NotFound/Disabled/NotStarted/Expired/UsesExhausted/NotAllowedForUser/InvalidReward)与 RuntimeProfileProcedureRejectionCode(聚合会员 / 兑换码两类码)
- RuntimeProfileRewardCodeRedeemProcedureResult 末尾追加 error_code,spacetime-module 用 ProfileRewardCodeRedeemProcedureError 在拒绝点显式赋码,入参与钱包错误保持无码
- SpacetimeClientError::ProcedureRejected.code 改为 RuntimeProfileProcedureRejectionCode,Display 输出 [code] message,不再吞掉机器可读原因(评审第 12 条)
- api-server 的 map_runtime_profile_client_error 只读变体字段,AppError.code 取 code.as_str(),删除 is_runtime_profile_domain_error / is_runtime_profile_redeem_code_domain_error 两个中文文案匹配函数
- 重新生成 Rust bindings;同步技术设计 §5.8 与 decision-log
This commit is contained in:
2026-10-04 18:40:54 +08:00
parent e91c319aa8
commit bd06e42690
10 changed files with 375 additions and 87 deletions
@@ -433,23 +433,31 @@ flowchart TD
- `npm run check:generated-bindings` 以「重新生成并与工作区逐字节比较」做门禁,防止 Rust 改了而生成文件没重跑。
- 需要展示用派生字段(如 `totalPoints` 合计)时,在前端 `utils/mudPoints.ts` 里派生,不改 DTO。
### 5.8 会员错误码契约(typed error,已落地)
### 5.8 Profile 错误码契约(typed error,已全面落地)
- 会员链路的业务拒绝不再靠中文 `error_message` 前缀分类。`module-runtime` 新增
`RuntimeProfileMembershipErrorCode`(`UpgradeRejected` / `NotMember` / `AlreadyActive` /
`CycleKindLocked` / `MembershipExpired` / `StateChanged` / `PlanNotPurchasable` /
`PlanCatalogMissing` / `ProductIdUnparsable` / `MembershipProductRetired` / `InvalidPlanConfig`),
在拒绝点显式产出,`RuntimeProfileMembershipUpgradeQuoteProcedureResult` /
- Profile 链路的业务拒绝不再靠中文 `error_message` 分类,全部由 procedure 结果里的机器可读
`error_code` 透传。
- 会员链路:`module-runtime` 的 `RuntimeProfileMembershipErrorCode`(`UpgradeRejected` /
`NotMember` / `AlreadyActive` / `CycleKindLocked` / `MembershipExpired` / `StateChanged` /
`PlanNotPurchasable` / `PlanCatalogMissing` / `ProductIdUnparsable` /
`MembershipProductRetired` / `InvalidPlanConfig`)在拒绝点显式产出,
`RuntimeProfileMembershipUpgradeQuoteProcedureResult` /
`RuntimeProfileRechargeCenterProcedureResult` / `RuntimeProfileMembershipPlanAdminProcedureResult`
末尾追加 `error_code: Option<RuntimeProfileMembershipErrorCode>`(`error_message` 保留人读文案)。
- `spacetime-client` 的 `SpacetimeClientError` 新增
`ProcedureRejected { code, message }`;`api-server` 的 `runtime_profile` 映射据此返回 400
(`provider = runtime-profile`),基础设施错误保持 502。字段校验类错误(如 user_id 缺失)
不产出 `error_code`,仍按字符串错误落到 502。
- 行为变化:`会员目录缺少档位 ...` 与「已迁移的会员商品」原先落到 502,现在有明确错误码,统一 400。
- 兑换码链路:`module-runtime` 的 `RuntimeProfileRewardCodeRedeemErrorCode`(`NotFound` /
`Disabled` / `NotStarted` / `Expired` / `UsesExhausted` / `NotAllowedForUser` /
`InvalidReward`)在拒绝点显式产出,`RuntimeProfileRewardCodeRedeemProcedureResult` 末尾同样追加
`error_code`。
- `spacetime-client` 的 `SpacetimeClientError::ProcedureRejected { code, message }` 用
`RuntimeProfileProcedureRejectionCode` 聚合两条链路的 typed code;`api-server` 的 `runtime_profile`
映射直接读变体字段返回 400(`provider = runtime-profile`),`AppError.code` 取
`code.as_str()`,基础设施错误保持 502。字段校验类错误(如 user_id 缺失)不产出 `error_code`,
仍按字符串错误落到 502。
- 行为变化:`会员目录缺少档位 ...`、「已迁移的会员商品」以及兑换码的 `兑换码不存在` / `已停用` /
`未生效` / `已过期` / `次数已用完` / `不适用于当前账号` / `奖励无效` 原先落到 502,现在有明确
错误码,统一 400。`api-server` 已删除 `is_runtime_profile_redeem_code_domain_error` 文案匹配函数。
- 兼容边界:procedure result 是 wire 结构,新增字段要求 module 与 api-server 同版本部署;
旧 module 不返回 `error_code` 时,新 client 绑定反序列化会失败。兑换码链路本轮未改造,
`api-server` 仍保留一个兑换码文案匹配函数。
旧 module 不返回 `error_code` 时,新 client 绑定反序列化会失败。
---