fix(admin): restore product visibility and code copying
Independent Staging Quality Gate / validate (push) Successful in 13m47s
Independent Staging Quality Gate / publish (push) Successful in 10m6s

This commit is contained in:
Jesse_Chen
2026-08-17 10:25:16 +08:00
parent 1cbdb774e0
commit 7050f7ee17
5 changed files with 71 additions and 1 deletions
+28
View File
@@ -3555,3 +3555,31 @@
- 防复发:跨响应、UI 状态和持久化边界共享的 receipt 必须只有一个 canonical schema;禁止在写入合同中复制 `.strict()` 子结构。新增字段必须以包含完整真实消息形状的 round-trip 回归验证。
- 相关记录:BUG-186、BUG-189
- 修复版本:本次 staging 发布候选(精确 SHA 以远端 staging 为准)
## BUG-212 | 管理端新生成兑换码复制为 `[object Object]`
- 状态:resolved(本地修复,待提交与发布)
- 首次发现:2026-08-17
- 最近更新:2026-08-17
- 影响面:管理端批量生成兑换码后的“完整兑换码(仅显示本次)”弹窗。
- 用户现象:完整兑换码在页面上显示正常,但点击复制图标后,剪贴板内容是 `[object Object]`,无法直接发送或兑换。
- 根因:Ant Design `Typography.Paragraph` 开启了布尔值 `copyable`,其直接子节点却是嵌套的 React `Typography.Text` 元素;组件默认复制子节点时把 React 元素对象字符串化,因而写入 `[object Object]`,而不是业务字段中的明文兑换码。
- 修复:为每个新生成兑换码的 `copyable` 显式指定 `text: record.code ?? ""`;显示仍使用 code 样式,完整明文仍只存在于本次创建响应与当前弹窗,不改变列表脱敏和服务端存储边界。
- 验证:兑换码管理源码合同锁定复制源必须是 `record.code`,禁止再次依赖嵌套 React 子节点的默认字符串转换;运行对应聚焦合同测试及 `git diff --check`
- 防复发:只要可复制 UI 的 children 不是直接字符串,就必须显式提供 copyable text;一次性秘密值不得从 mask、ReactNode 或对象隐式转换。
- 相关记录:BUG-207、BUG-209
- 修复版本:本地未提交候选
## BUG-213 | 会员页显示预置套餐但管理端商品列表为空
- 状态:resolved(本地修复,待提交、迁移与发布)
- 首次发现:2026-08-17
- 最近更新:2026-08-17
- 影响面:管理端商品列表与详情;会员页公开套餐读取的数据来源说明。
- 用户现象:会员页显示“体验卡 / 标准月卡 / 标准年卡”,但 `GET /api/admin/products` 返回 `{"data":[],"total":0}`,看起来像套餐被前端写死且无法在后台管理。
- 根因:套餐不是前端常量,而是 `20260806020000_billing_products_subscriptions.sql` 预置到 `billing_products` / `product_entitlements` 的默认发布商品。公开 `/api/payment/packages` 通过 `service_runtime` 能读取这些记录;管理 API 通过受限 `admin_runtime` 查询。原迁移虽然授予 `admin_runtime` 表级 SELECT,但两张表已启用 RLS,且只创建了 anon/authenticated 公开策略,遗漏 admin_runtime SELECT policy,导致合法管理查询被 RLS 静默过滤为零行。
- 修复:新增向前迁移,为 `admin_runtime` 重新授予 `billing_products``product_entitlements` SELECT,并分别创建 `using (true)` 的管理员只读策略。API 仍先执行 `billing.products.read` 权限校验;未给 admin_runtime 增加 service_role 成员关系,也未放开直接写表,保存与发布继续只能经过既有审计 RPC。
- 验证:数据库回归以真实 `admin_runtime` 连接读取预置 `standard_monthly` 商品及其 3 条权益;同时保留无法 `set role service_role` 与敏感 Profile 列不可读断言。发布后还需确认管理商品接口不再为空,并与公开套餐接口中的商品 ID/版本一致。
- 防复发:对启用 RLS 的管理资源,table grant 与 RLS policy 必须成对验证;后台列表测试必须使用 `admin_runtime` 真实角色,不能只用 schema owner 绕过 RLS。
- 相关记录:BUG-156、BUG-209
- 修复版本:本地未提交候选