# 7月迭代禅道研发需求逐条录入稿

> 用法：每条研发需求分别复制“标题”和“描述”到禅道。前端描述已包含页面结构、交互状态和接口契约，可先按 Mock 开发；后端描述包含业务规则和交付边界。
>
> 公共约定：接口统一返回 `{code,msg,data,timestamp}`，下文只写 `data`；金额单位为分；时间为 ISO 8601；分页结构为 `{items,total,page,size}`；状态判断使用 `status`，中文展示使用 `status_name`。返回字段除明确标注 `null` 或“特定状态返回”外均为必返字段，前端 Mock 不得自行改名或改变类型。

## 工时口径

- 单位为人时，1人日按8小时计算。
- FE/BE工时包含实现、自验、关联联调问题修复，不包含等待企微、支付、Gateway等外部配置的时间。
- INT-01～INT-07用于组织联调，不重复增加总工时；如禅道必须填写联调工时，应从关联FE/BE研发需求中拆出同等工时。
- INT-08为额外的全链路验收和停机发布准备，前端3～4小时、后端4～5小时。
- 按逐条工时汇总并去除联调重复计算后：前端58.5～89小时，后端92.5～127.5小时；对外取整仍为前端59～89小时、后端93～128小时。
- 总体仍按1前端+1后端并行12～15个工作日、风险上限16个工作日执行。

## UR#98 换货管理新资产归属

### 前端研发需求

**标题**

```text
[FE][UR#98] 换货新资产归属继承提示
```

**描述**

```markdown
目标：换货操作时明确新资产最终归属，避免运营误认为可以手工选择目标店铺。

预计工时：前端0.5～1小时。

页面入口：现有换货创建页、发货确认页、换货详情页。

页面结构：
1. 选择旧资产后展示旧资产所属店铺。
2. 选择新资产后增加只读提示“换货完成后将归属：{店铺名称}”。
3. 不增加目标店铺选择控件。
4. 详情页展示继承后的店铺名称。

接口约定：
- 复用 POST /api/admin/exchanges、POST /api/admin/exchanges/{id}/ship、POST /api/admin/exchanges/{id}/complete。
- 创建入参沿用旧资产、新资产、换货类型和资料迁移字段。
- 返回 data 增加 inherited_shop_id:int64、inherited_shop_name:string。

交互规则：新资产属于其他店铺时展示后端错误；提交期间禁用按钮；成功后重新拉取详情。

完成标准：创建、发货、完成三个页面均能正确展示目标店铺，并覆盖加载中、失败和重复提交状态。
```

### 后端研发需求

**标题**

```text
[BE][UR#98] 换货新资产继承旧资产店铺
```

**描述**

```markdown
目标：换货完成时由系统自动维护新资产归属，不允许前端指定目标店铺。

预计工时：后端1～1.5小时。

接口：复用 POST /api/admin/exchanges、POST /api/admin/exchanges/{id}/ship、POST /api/admin/exchanges/{id}/complete。

规则：
1. 新资产允许处于平台库存，或已经属于旧资产店铺；属于其他店铺时拒绝。
2. 完成换货事务内迁移新资产 shop_id、租户标签和资产分配记录，再迁移客户、钱包、套餐和状态。
3. 旧资产保留原 shop_id，仅更新为已换货状态。
4. 返回 inherited_shop_id、inherited_shop_name，写入换货审计。

架构：换货完成逻辑迁入 exchange Domain，旧 Service 不保留第二套完成逻辑。

完成标准：跨资产数据在同一事务内一致，重复完成保持幂等，其他店铺资产不能被越权换入。
```

## UR#97 代理钱包阈值提醒

### 前端研发需求

**标题**

```text
[FE][UR#97] 代理现金余额不足100元展示
```

**描述**

```markdown
目标：现金可用余额不足100元时给运营明确提示，不提供阈值配置。

预计工时：前端0.5～1小时，不含公共站内通知页面工时。

页面入口：代理资金概况、顶部通知抽屉、站内通知中心。

页面结构：
1. 资金概况显示现金余额、冻结金额和“现金余额不足100元”红色状态。
2. 不展示阈值输入框，不把信用额度计入预警文案。
3. 通知点击后跳转对应店铺资金页。

接口约定：
- GET /api/admin/shops/fund-summary 返回 balance:int64、frozen_balance:int64、cash_available:int64、low_balance_warning:bool。
- 通知复用 GET /api/admin/notifications，目标解析复用 GET /api/admin/notifications/{id}/target。

交互规则：只使用 low_balance_warning 控制提示，不由前端自行计算阈值；金额按分转元展示。

完成标准：余额高于、等于、低于100元三种状态展示正确，通知能跳转且无权限时按统一错误页处理。
```

### 后端研发需求

**标题**

```text
[BE][UR#97] 代理主钱包固定100元余额预警
```

**描述**

```markdown
目标：主钱包现金可用余额跨越固定阈值时可靠发送一次站内通知。

预计工时：后端1～1.5小时，不含公共站内通知基础设施工时。

规则：
1. cash_available=balance-frozen_balance，不包含信用额度。
2. 变动前>10000分且变动后<=10000分时发送通知。
3. 余额回升到10000分以上后重新布防；持续低余额不重复发送。
4. 接收人为店铺主账号和可用的店铺业务员。

接口：GET /api/admin/shops/fund-summary 增加 cash_available、low_balance_warning；通知复用现有通知接口。

实现：钱包聚合产生低余额领域事件，事务内写 Outbox，通知使用稳定业务键防重并记录审计。

完成标准：扣款、冻结、解冻、充值和退款回充都能正确触发或重新布防，通知失败不回滚资金事务。
```

## UR#96 员工作为发展人进行标识

### 前端研发需求

**标题**

```text
[FE][UR#96] 店铺业务员选择展示与筛选
```

**描述**

```markdown
目标：为店铺绑定平台业务员，只表示业务归属和通知关系。

预计工时：前端0.5～1小时。

页面入口：店铺新建、店铺编辑、店铺列表、店铺详情。

页面结构：
1. 超级管理员和平台账号的新建、编辑表单增加“平台业务员”可搜索下拉，可为空；代理账号只读展示，不出现选择或清空控件。
2. 候选项展示账号名和手机号摘要，只显示启用的平台账号。
3. 店铺列表增加业务员列和业务员筛选项。
4. 店铺详情展示业务员名称和手机号摘要。
5. 代理创建下级店铺时提示“默认继承直属上级当前业务员”；继承由后端保证。

接口约定：
- POST /api/admin/shops、PUT /api/admin/shops/{id} 增加 business_owner_account_id:int64|null。
- GET /api/admin/shops 增加 business_owner_account_id 查询参数。
- 业务员候选复用 GET /api/admin/accounts?account_type=platform&status=1，items至少返回 account_id、account_name、phone_masked。
- 列表和详情返回 business_owner_account_id:int64|null、business_owner_name:string、business_owner_phone_masked:string。

交互规则：不出现分销、佣金或发展层级文案；代理不能通过构造请求修改业务员；已停用业务员仍可在历史详情显示，但编辑候选中不可选；上级店铺后续变更不自动级联既有下级。

完成标准：创建、编辑、筛选、详情展示一致，并覆盖清空业务员和无可选账号状态。
```

### 后端研发需求

**标题**

```text
[BE][UR#96] 店铺业务员关联与查询
```

**描述**

```markdown
目标：保存店铺的平台业务员归属，并用于查询和站内通知接收人计算。

预计工时：后端1～1.5小时。

数据：tb_shop 增加 business_owner_account_id，可空，不建立数据库外键。

接口：POST /api/admin/shops、PUT /api/admin/shops/{id} 支持 business_owner_account_id；GET /api/admin/shops 支持同名筛选；列表和详情返回账号名称及手机号摘要。

规则：
1. 只允许绑定启用的平台账号。
2. 字段不参与店铺层级、数据权限、佣金或分销关系计算。
3. 账号停用或删除后保留历史关联，通知时跳过不可用账号。
4. 变更前后值写入审计。
5. 代理创建下级店铺时由服务端复制所选直属上级店铺当时的业务员；代理请求只要出现该字段即拒绝。
6. 只有超级管理员和平台账号可以显式设置、清空或更换；父店铺后续变更不向既有子孙店铺级联。

完成标准：创建、修改、清空和筛选均生效，不能绑定代理账号或停用平台账号。
```

## UR#94 系统状态同步优化以及回调处理

### 前端研发需求

**标题**

```text
[FE][UR#94] 资产同步状态与同步轨迹入口
```

**描述**

```markdown
目标：让运营通过统一审计查看业务事件和回调的同步轨迹；保留现有手动刷新和轮询展示，不新增第二个同步按钮或活跃轮询字段。

预计工时：前端2～3小时。

页面入口：卡详情、设备详情、全局审计外部集成页。

页面结构：
1. 保留现有手动刷新按钮及现有轮询状态展示，不新增活跃级别、最后活跃场景或下次轮询字段。
2. 增加“查看同步轨迹”，跳转全局审计并自动带入资产筛选。
3. 同步轨迹按立即、3分钟、5分钟连续展示结果，并显示运营商回调和现有周期轮询的Integration Log。

接口约定：
- 现有手动刷新接口保持原契约。
- GET /api/admin/audit/integrations 支持 resource_type、resource_key、correlation_id 查询。

交互规则：事件序列的rate_limited只展示本次失败，不显示自动退避倒计时；前端不根据事件轨迹推算或展示新的周期轮询时间。

完成标准：卡和设备均能展示同步状态并跳转到过滤后的轨迹页，加载、空记录和失败状态完整。
```

### 后端研发需求

**标题**

```text
[BE][UR#94] 卡状态公共写入、事件触发与运营商实名回调
```

**描述**

```markdown
目标：将现有轮询查询结果、业务事件、手动刷新和运营商回调统一进入卡状态应用用例，同时保持现有轮询调度不变。

预计工时：后端7～9小时。

规则：
1. 现有tb_polling_config、Redis分片队列、各同步类型间隔、卡级开关、失败重排、并发控制和监控全部保持现状，只替换查询成功后的状态写入及联动。
2. 关键业务成功边界创建立即、3分钟、5分钟三个无自动重试任务；达到预期状态后后续任务提前完成。
3. Gateway 超频只记录 rate_limited，不做 blocked_until 或指数退避。
4. ApplyCardObservation 是实名、流量和网络状态的唯一写入口。
5. 行业卡是否实名由运营商 realname_link_type 决定。

接口：不新增显式同步接口或活跃轮询字段；现有手动刷新保持原契约；同步轨迹进入统一Integration Log和审计Query；只为已掌握真实报文的移动/电信实名成功及联通解除实名增加回调Translator。

架构：迁移到 card Domain、同步 Application、Gateway Adapter 和 Query，旧轮询及刷新逻辑改为调用统一用例。

完成标准：现有轮询、事件序列、手动刷新和回调结果一致，事件序列可追踪，旧逻辑不再直接修改卡状态；改造前后轮询配置、下次入队、失败重排和监控统计保持一致。
```

## UR#86 资产详情中换货标识

### 前端研发需求

**标题**

```text
[FE][UR#86] 资产详情前代后代换货标识
```

**描述**

```markdown
目标：在资产详情中明确当前资产在换货链中的位置。

预计工时：前端0.5～1小时。

页面入口：卡详情、设备详情。

页面结构：
1. previous_asset 存在时显示“换货新资产”标签和前代资产信息。
2. next_asset 存在时显示“已换出旧资产”标签和后代资产信息。
3. 中间资产可同时显示前代和后代。
4. can_view=true 时支持点击跳转；false 时只显示标识文本。

接口约定：GET /api/admin/assets/resolve/{identifier} 返回 exchange_trace.previous_asset 和 exchange_trace.next_asset；单项结构为 asset_type:string、asset_id:int64|null、identifier:string、exchange_no:string、can_view:bool。

交互规则：不根据换货状态自行拼链路；关联资产为空时不展示对应区域。

完成标准：旧资产、新资产、链路中间资产和无权限四类状态均显示正确。
```

### 后端研发需求

**标题**

```text
[BE][UR#86] 资产换货链Query
```

**描述**

```markdown
目标：基于已完成换货单返回资产前代和后代关系。

预计工时：后端1～1.5小时。

接口：GET /api/admin/assets/resolve/{identifier} 增加 exchange_trace.previous_asset、exchange_trace.next_asset。

返回结构：asset_type、asset_id、identifier、exchange_no、can_view；无权限时 asset_id 返回 null，仍可返回脱敏后的标识和 can_view=false。

规则：复用 tb_exchange_order，不新建换货关系表；只使用已完成换货单；补充旧资产和新资产查询索引；查询遵守现有数据范围。

完成标准：卡和设备均可查询前后关系，无 N+1，越权用户不能获得可跳转资源 ID。
```

## UR#73 行业卡操作停复机

### 前端研发需求

**标题**

```text
[FE][UR#73] 复机实名校验提示适配
```

**描述**

```markdown
目标：沿用现有复机入口，根据后端实名规则展示结果，不在前端按行业卡类型放行。

预计工时：前端0.5～1小时。

页面入口：卡详情、设备详情的复机操作。

页面结构：保持现有复机确认框；失败时原地展示后端中文业务原因。

接口约定：复用 POST /api/admin/assets/{identifier}/start；成功返回最新资产 status、status_name、real_name_status、real_name_status_name。

交互规则：前端不读取 card_category 判断实名要求；提交中禁用按钮；成功后重新拉取详情。

完成标准：同为行业卡但运营商实名能力不同的情况下，页面能正确展示放行或拦截结果。
```

### 后端研发需求

**标题**

```text
[BE][UR#73] 按运营商实名能力控制复机
```

**描述**

```markdown
目标：删除“行业卡统一无需实名”的错误规则。

预计工时：后端1小时。

接口：复用 POST /api/admin/assets/{identifier}/start。

规则：
1. realname_link_type=none 时允许未实名复机。
2. realname_link_type=template 或 gateway 时仍要求实名。
3. card_category 只用于分类展示，不参与复机判断。
4. 复机成功后触发实名、流量和网络状态的0/3/5同步序列。

架构：复机资格进入卡状态 Domain 规则，Handler/Service 不保留行业卡分支。

完成标准：不同运营商特性的行业卡行为正确，错误返回统一业务错误码并写审计。
```

## UR#62 H5设置先充值后实名

### 前端研发需求

**标题**

```text
[FE][UR#62] H5实名购买顺序与后台批量配置
```

**描述**

```markdown
目标：支持无需实名、先实名后购买、先购买后实名三种流程，并提供后台批量配置。

预计工时：前端2～3小时。

页面入口：C端资产初始化流程；后台卡列表和设备列表。

页面结构：
1. C端按 effective_realname_policy 决定直接购买、先实名或购买后提示实名。
2. 后台卡和设备列表分别增加“批量修改实名顺序”入口。
3. 弹框提供无需实名、先实名后购买、先购买后实名三选一，并展示已选数量。
4. 修改设备下卡策略时提示“实际H5流程由设备策略决定”。

接口约定：
- PATCH /api/admin/assets/{identifier}/realname-mode，入参 realname_policy:none|before_order|after_order。
- POST /api/admin/iot-cards/batch-update-realname-policy、POST /api/admin/devices/batch-update-realname-policy，入参 asset_ids:int64[]、realname_policy:string。
- C端初始化返回 effective_realname_policy:string、realname_required:bool、realname_status:int。

交互规则：单次最多500条；批量接口全成全败；前端不根据资产类型自行覆盖策略。

完成标准：三种C端流程和卡/设备批量配置均可运行，冲突数据能展示明确错误。
```

### 后端研发需求

**标题**

```text
[BE][UR#62] 资产实名顺序策略与批量配置
```

**描述**

```markdown
目标：统一独立卡、设备和设备下卡的有效实名顺序计算。

预计工时：后端3～4小时。

接口：PATCH /api/admin/assets/{identifier}/realname-mode；POST /api/admin/iot-cards/batch-update-realname-policy；POST /api/admin/devices/batch-update-realname-policy。

规则：
1. 独立卡读取卡策略；设备及设备下卡读取设备策略。
2. realname_link_type=none 时有效策略固定为 none。
3. 需要实名的运营商配置为 none 属于冲突数据，运行时拒绝静默放行。
4. 批量最多500条，事务内全成全败。
5. 新资产默认 after_order。

完成标准：单条和批量配置使用同一校验规则，C端只需读取有效策略，配置变更写审计。
```

## UR#60 店铺联系电话检索

### 前端研发需求

**标题**

```text
[FE][UR#60] 店铺联系电话搜索控件
```

**描述**

```markdown
目标：在店铺列表按11位联系电话精确检索。

预计工时：前端0.5～1小时。

页面入口：店铺列表筛选区。

页面结构：增加“联系电话”输入框、查询按钮和清空能力；输入框限制11位数字。

接口约定：GET /api/admin/shops?contact_phone=13800138000，返回原店铺分页结构。

交互规则：空值不传参数；非法号码不发请求并提示；清空后恢复原列表条件。

完成标准：有效号码精确命中，空结果、加载和参数错误状态完整。
```

### 后端研发需求

**标题**

```text
[BE][UR#60] 店铺联系电话精确查询
```

**描述**

```markdown
目标：扩展店铺列表Query，支持联系电话精确查询。

预计工时：后端0.5～1小时。

接口：GET /api/admin/shops 增加 contact_phone 查询参数。

规则：只接受合法11位手机号；空参数不影响原查询；查询继续应用现有数据权限和分页。

完成标准：命中、未命中、非法参数和越权数据范围均符合统一接口规范，查询可使用现有联系电话索引或补充必要索引。
```

## UR#57 退款中禁止换货

### 前端研发需求

**标题**

```text
[FE][UR#57] 换货退款拦截错误展示
```

**描述**

```markdown
目标：创建换货时直接展示后端的退款拦截结果。

预计工时：前端0.5～1小时。

页面入口：换货创建页。

页面结构：不新增退款状态查询和预检查区域；提交失败时在表单顶部或资产行展示“该资产存在退款申请”。

接口约定：复用 POST /api/admin/exchanges；错误使用统一 code、msg，不改变成功返回结构。

交互规则：前端不自行判断审批或退款处理状态；失败后保留已填写表单，允许更换资产后重新提交。

完成标准：存在活跃退款时不进入下一步，已拒绝、撤销或处理完成的资产可正常换货。
```

### 后端研发需求

**标题**

```text
[BE][UR#57] 换货前活跃退款校验
```

**描述**

```markdown
目标：换货创建前统一拦截仍可能影响资产和资金状态的退款申请。

预计工时：后端1～1.5小时。

接口：复用 POST /api/admin/exchanges。

规则：企微审批中、历史已退回、企微已通过但退款业务处理未完成时禁止换货；已拒绝、已撤销、已删除或退款处理完成后放行。

实现：按提交资产批量查询活跃退款，禁止逐资产N+1；返回统一错误“该资产存在退款申请”；校验与换货创建保持一致性。

完成标准：所有退款状态边界明确，批量换货场景能指出失败资产且不产生半成品换货单。
```

## UR#55 套餐生效条件

### 前端研发需求

**标题**

```text
[FE][UR#55] 套餐分配生效条件选择
```

**描述**

```markdown
目标：允许代理套餐分配覆盖套餐默认生效条件，并明确只影响未来购买。

预计工时：前端1.5～2.5小时。

页面入口：套餐授权/分配弹框、已分配套餐详情或编辑弹框。

页面结构：
1. 增加“生效条件”单选：跟随套餐默认、购买即生效、实名即生效。
2. 同时展示 default_expiry_base、override_expiry_base 和 effective_expiry_base 的中文名称。
3. 修改时提示“仅影响后续新订单，不影响已购买套餐”。

接口约定：
- POST /api/admin/shop-package-allocations，入参增加 expiry_base_override:string|null。
- PATCH /api/admin/shop-package-allocations/{id}/expiry-base，body 为 {expiry_base_override:null|"from_purchase"|"from_realname"}。
- 返回 default_expiry_base、expiry_base_override、effective_expiry_base 及对应 name 字段。

交互规则：选择“跟随默认”必须显式发送 null；不能省略字段代替恢复默认。

完成标准：新建、修改、恢复默认均可用，页面能区分默认值、覆盖值和最终值。
```

### 后端研发需求

**标题**

```text
[BE][UR#55] 套餐分配生效条件覆盖与购买快照
```

**描述**

```markdown
目标：建立“套餐默认→代理分配覆盖→购买使用记录快照”的完整规则。

预计工时：后端2.5～3.5小时。

接口：POST /api/admin/shop-package-allocations；PATCH /api/admin/shop-package-allocations/{id}/expiry-base。

数据：分配表增加 nullable expiry_base_override；PackageUsage 增加 expiry_base、周期类型和时长快照字段。

规则：null表示跟随默认；购买时计算有效值并写入快照；后续修改套餐或分配配置不影响已购买记录；旧数据仅做兼容回退。

架构：购买快照和激活规则进入套餐生命周期 Domain；查询侧返回默认、覆盖和最终值。

完成标准：新旧订单行为可区分，排队套餐激活和最终到期推算只读取购买快照。
```

## UR#53 资产实名状态筛选

### 前端研发需求

**标题**

```text
[FE][UR#53] 卡和设备实名状态筛选
```

**描述**

```markdown
目标：在卡和设备列表按实名状态筛选并展示状态。

预计工时：前端1～2小时。

页面入口：卡列表、设备列表。

页面结构：筛选区增加全部、已实名、未实名；表格增加“实名状态”列，展示 real_name_status_name。

接口约定：
- GET /api/admin/iot-cards?real_name_status=0|1。
- GET /api/admin/devices?real_name_status=0|1。
- items 返回 real_name_status:int、real_name_status_name:string。

交互规则：设备状态直接使用接口结果，不在前端遍历绑定卡计算。

完成标准：卡和设备的全部、已实名、未实名筛选正确，分页切换保留筛选条件。
```

### 后端研发需求

**标题**

```text
[BE][UR#53] 卡设备实名状态查询与设备快照
```

**描述**

```markdown
目标：提供统一实名状态筛选，设备状态由有效绑定卡快照维护。

预计工时：后端2～3小时。

接口：GET /api/admin/iot-cards、GET /api/admin/devices 增加 real_name_status=0|1。

规则：卡读取自身实名状态；设备存在任一有效绑定实名卡即为已实名；实名变化、绑定、解绑和换卡时刷新旧设备及新设备快照。

返回：real_name_status、real_name_status_name；查询继续应用现有分页和数据权限。

完成标准：设备快照不因换卡残留，列表查询不做逐设备子查询，历史数据完成一次性初始化。
```

## UR#49 设备批量分配代理和套餐系列

### 前端研发需求

**标题**

```text
[FE][UR#49] 设备批量分配代理与套餐系列双入口
```

**描述**

```markdown
目标：把“批量分配代理”和“批量分配套餐系列”作为两个独立功能，复用同一任务进度交互。

预计工时：前端2～3小时。

页面入口：设备列表工具栏。

页面结构：
1. 两个独立按钮：批量分配代理、批量分配套餐系列。
2. 两个弹框都包含前端静态CSV模板下载、目标选择、CSV上传和提交按钮；不接受Excel。
3. 创建成功后进入任务进度区，展示状态、总数、成功数、失败数和失败明细。
4. 页面刷新后根据 task_id 恢复进度。

接口约定：
- 前端先调用现有对象存储预签名上传接口，purpose=device_batch_allocation，将UTF-8 CSV直传私有对象存储。
- POST /api/admin/devices/batch-assign-shop，JSON body={file_key,shop_id}。
- POST /api/admin/devices/batch-assign-series，JSON body={file_key,series_id}。
- GET /api/admin/devices/batch-allocation/{task_id} 返回 task_id、operation_type、status、status_name、total_count、success_count、failed_count、failed_items。

交互规则：一个任务只能选择一种操作；任务处理中按2、3、5秒后最大10秒轮询；页面不可见时暂停。

完成标准：两个入口互不混淆，平台代理权限与现有同步用例一致，长设备号按文本预览，部分成功和失败原因可查看，CSV模板由前端静态文件提供。
```

### 后端研发需求

**标题**

```text
[BE][UR#49] 设备两类批量分配任务
```

**描述**

```markdown
目标：使用统一批量基础设施分别执行设备代理分配和套餐系列分配。

预计工时：后端3～4小时。

接口：POST /api/admin/devices/batch-assign-shop；POST /api/admin/devices/batch-assign-series；GET /api/admin/devices/batch-allocation/{task_id}。

规则：
1. operation_type 只能是 assign_shop 或 assign_series，一个任务只修改一个目标字段。
2. 只接受单列UTF-8 CSV，固定表头“设备号”；文件最大10MB、最多1000行、Worker每批200条。
3. 设备号去重后批量查询；失败明细最多保存1000条。
4. 平台只能分配平台库存；代理只能把自己名下设备分给直属下级。assign_series时代理只能操作自己设备并使用自己当前授权系列。
5. 已属于目标值按幂等成功；assign_shop遇到其他代理资产失败；assign_series不修改shop_id。
6. 业务接口只接收file_key，不接收multipart字节；Asynq载荷只传结构化task_id，不传对象Key、本地路径或文件字节。

完成标准：任务支持部分成功和进度恢复，Worker重试幂等，平台及代理数据边界正确，两种命令的数据边界清晰。
```

## UR#48 不同资产使用不同支付方式

### 前端研发需求

**标题**

```text
[FE][UR#48] C端按资产展示允许支付方式
```

**描述**

```markdown
目标：C端支付页只展示当前资产允许使用的支付方式。

预计工时：前端1.5～2.5小时。

页面入口：卡和设备的套餐购买、充值支付页；后台系统配置页。

页面结构：
1. 支付方式使用单选列表，只渲染 allowed_payment_methods 中的选项。
2. 没有可用方式时展示原因并禁用提交。
3. 后台配置使用卡/设备两个分组的复选框，不允许直接编辑JSON。

接口约定：
- GET /api/c/v1/asset/info 返回 allowed_payment_methods:string[]，值为 alipay、wechat、wallet。
- POST /api/c/v1/orders/create 必须提交payment_method:string并固化；POST /api/c/v1/orders/{id}/pay 不允许选择或修改payment_method，只提交固定方式执行所需附加参数。
- GET /api/admin/system/config?module=payment 查询配置；PUT /api/admin/system/config/{config_key} 保存卡和设备允许的支付方式。

交互规则：钱包是否可选完全使用后端返回；创建成功后展示订单已选方式且不提供切换。需要换方式时先取消待支付订单再重新创建；强充由创建接口按所选微信/支付宝立即拉起，钱包不能用于给自身强充。

完成标准：卡、设备、配置异常和无可用方式四类场景展示正确。
```

### 后端研发需求

**标题**

```text
[BE][UR#48] 资产支付方式配置与订单校验
```

**描述**

```markdown
目标：按资产类型返回允许支付方式，在订单创建时决定并固化支付方式，并在后续实际支付时再次强校验。

预计工时：后端2～3小时。

接口：GET /api/c/v1/asset/info 增加 allowed_payment_methods；订单创建和支付接口校验 payment_method；后台复用系统配置接口。

规则：卡默认支付宝和钱包；设备默认微信和钱包；钱包始终允许；配置异常时使用安全默认值并记录错误，不能放开全部方式。普通订单创建保存不可变payment_method，/pay只能读取订单快照执行；管理员后来禁用该方式时拒绝支付，不自动换渠道。强充在创建流程立即使用所选方式，wallet强充拒绝。

完成标准：前端隐藏不能绕过后端校验，订单创建和支付使用同一策略，配置变更写审计。
```

## UR#47 限速规则

### 前端研发需求

**标题**

```text
[FE][UR#47] IoT 卡手动设置固定限速档位
```

**描述**

```markdown
目标：仅在 IoT 卡详情提供手动固定档位限速入口，不展示自动限速规则。

预计工时：前端1～2小时。

页面入口：IoT 卡详情；设备详情不提供限速入口。

页面结构：
1. “手动限速”弹框只展示 `code=-1..8` 固定档位，不允许输入任意速率。
2. “恢复不限速”提交 `code=-1`；“限到0kbps”提交 `code=0`，两者严格区分。
3. 不展示“Gateway当前实际限速”，除非接口未来明确返回查询结果。

接口约定：`PUT /api/admin/iot-cards/{iccid}/speed-tier`，`body={code:int}`；返回 `iot_card_id/iccid/code/speed_tier_name/integration_id`。

交互规则：提交中禁用按钮；失败保留所选档位；结果未知不能显示成功，并提示按 ICCID 核对 Gateway 实际档位。

完成标准：卡固定档位、恢复不限速、越权卡、明确失败和结果未知场景完整；设备无入口。
```

### 后端研发需求

**标题**

```text
[BE][UR#47] Gateway按卡ICCID设置固定限速档位
```

**描述**

```markdown
目标：只开放 IoT 卡手动限速接口，按卡 ICCID 调用 Gateway。

预计工时：后端2～3小时。

接口：`PUT /api/admin/iot-cards/{iccid}/speed-tier`，入参为固定整数档位 `code=-1..8`；恢复不限速与限到0kbps分别使用 `-1` 和 `0`。

规则：按 ICCID 查询 IoT 卡并沿用现有数据权限；只向 `POST /flow-card/speedLimit` 发送 `cardNo + code`。设备没有限速入口，也不得解析设备当前绑定卡间接调用。外部副作用关闭盲目自动重试，超时等结果不明记录 `unknown`。

非目标：不建立套餐固定限速，不因激活、到期、停机或切卡自动限速，不增加自动补偿Worker。

完成标准：返回卡 ID、ICCID、固定档位和 Integration Log ID；明确失败和结果未知均有正确行为；每次请求记录操作审计及 Integration Log。
```

## UR#46 资产信息详情字段新增

### 前端研发需求

**标题**

```text
[FE][UR#46] 预计最终到期时间展示
```

**描述**

```markdown
目标：资产层只展示当前及全部排队主套餐接续后的一个预计最终到期时间。

预计工时：前端1.5～2.5小时。

页面入口：卡详情、设备详情和相关资产列表。

页面结构：
1. 字段名称统一为“预计套餐到期时间”。
2. exact 时展示 estimated_final_expires_at。
3. waiting_activation 等不可预计状态展示“待激活后起算”，不伪造日期。
4. is_expiring=true 时按剩余天数使用临期颜色，普通资产列表不改变排序。

接口约定：GET /api/admin/assets/resolve/{identifier} 及资产列表返回 estimated_final_expires_at:string|null、days_until_final_expiry:int|null、expiry_estimate_status:string、is_expiring:bool。

交互规则：当前套餐自身到期时间仅保留在套餐明细；前端不叠加套餐时长自行计算。

完成标准：无套餐、仅当前套餐、存在多个排队套餐和等待未知激活时间四类状态正确。
```

### 后端研发需求

**标题**

```text
[BE][UR#46] 当前及排队套餐最终到期Query
```

**描述**

```markdown
目标：统一计算资产当前生效及全部排队主套餐连续接续后的预计最终到期时间。

预计工时：后端3～4小时。

接口：资产详情和列表Query返回 estimated_final_expires_at、days_until_final_expiry、expiry_estimate_status、is_expiring。

规则：按套餐队列顺序和购买时长快照推演；无套餐返回null；等待无法确定时间的实名激活时返回不可预计状态；临期、导出和C端复用同一Query。

完成标准：不维护第二套资产汇总到期字段，查询避免N+1，边界按Asia/Shanghai自然日计算。
```

## UR#45 换货管理

### 前端研发需求

**标题**

```text
[FE][UR#45] 换货新旧资产展示与独立搜索
```

**描述**

```markdown
目标：换货列表能分别检索和识别旧资产、新资产。

预计工时：前端1～2小时。

页面入口：换货管理列表。

页面结构：
1. 筛选区拆为“旧资产”和“新资产”两个输入框。
2. 表格分别展示旧资产类型、旧资产标识、新资产类型、新资产标识。
3. 卡统一展示ICCID，设备展示设备号。

接口约定：GET /api/admin/exchanges?old_asset_keyword=&new_asset_keyword=；items返回 old_asset_type、old_asset_id、old_asset_identifier、new_asset_type、new_asset_id、new_asset_identifier、status、status_name。

交互规则：两个条件可单独或组合查询；空条件不传；不在前端转换接入号或虚拟号。

完成标准：旧资产和新资产不会混列，ICCID、接入号、虚拟号均可通过后端命中对应卡。
```

### 后端研发需求

**标题**

```text
[BE][UR#45] 换货标识快照修正与新旧资产查询
```

**描述**

```markdown
目标：规范换货单的新旧资产标识，并支持独立查询。

预计工时：后端1～2小时。

接口：GET /api/admin/exchanges 增加 old_asset_keyword、new_asset_keyword。

规则：卡的新旧资产快照统一保存ICCID，设备保存设备号；查询卡时支持ICCID、接入号和虚拟号映射；历史记录不强制回填；新建换货使用规范化标识。

完成标准：两个筛选条件可组合，查询遵守数据权限并具备必要索引，大结果集不出现逐行反查。
```

## UR#44 列表字段新增

### 前端研发需求

**标题**

```text
[FE][UR#44] 退款充值换货列表提交人与审批摘要
```

**描述**

```markdown
目标：在业务列表直接看到谁提交、企微审批到哪一步、业务是否处理完成。

预计工时：前端1～2小时。

页面入口：退款列表、代理充值列表、换货列表。

页面结构：增加提交人、审批状态、当前审批人摘要、业务处理状态四列；历史本地审批显示“历史审批”，不提供操作按钮。

接口约定：GET /api/admin/refunds、GET /api/admin/agent-recharges、GET /api/admin/exchanges 的items增加 submitter_name、approval_source、approval_status、approval_status_name、current_approver_summary、processing_status、processing_status_name。

交互规则：approval_source=none时审批列显示“-”；legacy只读展示；wecom展示企微状态。平台/超级管理员按业务权限展示当前审批人摘要，长摘要使用省略和悬浮完整文本；代理不展示审批人列，接口摘要固定为空。

完成标准：三类列表字段和空值规则一致，分页切换不会额外逐行请求审批详情。
```

### 后端研发需求

**标题**

```text
[BE][UR#44] 提交人快照与企微审批摘要批量查询
```

**描述**

```markdown
目标：为退款、充值和换货列表提供统一提交人及审批摘要。

预计工时：后端2～3小时。

接口：扩展现有三类列表返回 submitter_name、approval_source、approval_status_name、current_approver_summary、processing_status_name。

规则：提交人保存业务快照；企微摘要按当前页实例ID批量查询，禁止N+1；历史本地审批返回approval_source=legacy；无审批返回none。当前审批人属于平台内部信息，仅平台/超级管理员按业务权限返回；代理响应中的current_approver_summary固定为空。

完成标准：列表查询次数稳定，历史数据可读，审批摘要与详情状态一致。
```

## UR#43 代理系列授权

### 前端研发需求

**标题**

```text
[FE][UR#43] 系列套餐批量选择与已授权置灰
```

**描述**

```markdown
目标：首次授权和后续追加套餐都支持批量选择，并明确哪些套餐已经授权。

预计工时：前端1～2小时。

页面入口：代理系列首次授权页、已授权系列的套餐管理页。

页面结构：
1. 两个入口复用同一套餐候选表格。
2. 首次授权读取现有套餐列表；后续管理再读取现有系列授权详情，前端按package_id合并，不新增候选接口。
3. 列按当前调用视角区分上级当前成本价、目标代理授权成本价、建议售价和授权状态；平台代理视角不得都误标为公司成本。
4. is_authorized=true的行在新增模式置灰；授权、调价、移除分别使用独立操作模式。
5. 未授权套餐支持多选并一次提交。

接口约定：
- 首次授权复用GET /api/admin/packages?series_id=...和POST /api/admin/shop-series-grants，POST必须同时提交至少一个packages项。
- 后续管理复用GET /api/admin/packages?series_id=...与GET /api/admin/shop-series-grants/{id}。
- PUT /api/admin/shop-series-grants/{id}/packages，body={packages:[{package_id,cost_price?,remove?}]}；`remove=true` 表示软删除，必须保持既有字段兼容。

交互规则：三类价格按分转元；提交成功后重新加载候选列表；空候选和全部已授权状态有明确提示。

完成标准：首次和后续授权行为一致，已授权套餐不能被再次选择。
```

### 后端研发需求

**标题**

```text
[BE][UR#43] 首次套餐授权与后续批量命令明确化
```

**描述**

```markdown
目标：首次授权继续同时创建系列与套餐；后续复用现有批量接口并保留 `packages[].remove` 已交付契约；不新增候选Query。

预计工时：后端0.5～1小时。

接口：复用GET /api/admin/packages、GET /api/admin/shop-series-grants/{id}、POST /api/admin/shop-series-grants和PUT /api/admin/shop-series-grants/{id}/packages。

首次授权：POST中的packages改为必填且至少1项，系列与套餐在同一事务全成全败，不允许空系列授权。

后续规则：PUT继续提交packages数组，`remove=true` 表示软删除，其他项按当前授权状态新增或改价；最多100项、事务内全成全败。不得要求必填operation_type或改变既有响应结构；所有系列、套餐、直属下级与价格边界由后端校验。

读取：前端组合现有套餐列表和授权详情；已授权但当前不在普通列表中的存量项仍从详情只读展示。成本字段按操作者视角准确命名。

完成标准：首次授权不会产生空系列；`packages[].remove` 兼容保留；重复提交不生成重复关系；旧前端无需切换新命令字段即可继续工作。
```

## UR#42 导出功能

### 前端研发需求

**标题**

```text
[FE][UR#42] 自动权限导出、角色字段配置与受保护附件访问
```

**描述**

```markdown
目标：用户按当前查询条件直接导出角色已授权的全部字段；管理员可给角色配置各场景可导出字段；导出文件中的退款/充值凭证和企微审批附件可通过后台登录态安全访问。

预计工时：按本冻结范围重新评估；原3～4小时估算未包含受保护附件落地页，不能继续沿用。

页面入口：卡、设备、订单、钱包流水、套餐、退款、换货、充值、临期列表的导出入口；角色权限配置页；后台附件落地页 `/export-attachments/:attachment_ref`。

页面结构：
1. 列表导出只选择xlsx/csv格式并沿用当前查询条件，不展示字段复选框；实际列完全由后端权限解析。
2. 页面可加载当前scene最终字段；返回空数组时禁用导出并提示“当前角色未配置该场景的导出字段”。
3. 创建后展示任务状态、进度、失败原因、取消和下载按钮；页面刷新后按任务ID恢复轮询。
4. 角色配置按scene分组展示代码支持字段，全量保存该角色单个scene的字段；允许清空，保存后重新读取服务端结果。
5. 新增受保护附件落地页，展示加载中、登录恢复、无权限/不存在、文件不可用、解析失败和成功跳转状态。

接口约定：
- GET /api/admin/export-fields?scene= 返回当前账号最终会导出的 fields:{key,label}[]；它不是字段选择候选集。
- POST /api/admin/export-tasks，body={scene,format,query}，返回 task_id；前端不得提交fields。
- GET /api/admin/export-tasks/{id} 返回 status、status_name、progress、download_url、error_message。
- GET/PUT /api/admin/roles/{role_id}/export-fields 查询代码目录及保存角色场景字段；PUT按单个scene全量替换，空数组表示收回全部字段。
- GET /api/admin/attachments/{attachment_ref}/download-url 返回 data:{download_url,expires_at,file_name}；请求必须携带后台当前Bearer Token。

导出流程：
1. 用户在列表页发起导出，前端提交scene、format和当前筛选条件；分页参数不进入导出条件。
2. 后端创建任务后，前端进入现有任务进度流程；download_url为空时禁用任务文件下载。
3. 导出文件中的附件地址是后台前端绝对地址 `{admin_frontend_base_url}/export-attachments/{attachment_ref}`，不是后端接口地址或对象存储地址。

附件访问流程：
1. 浏览器打开附件落地页；未登录时保存当前站内路径并进入后台登录，登录成功后返回该附件页。
2. 页面从路由读取attachment_ref，使用Bearer Token调用附件解析接口；禁止把attachment_ref替换为file_key，也禁止接收外部returnUrl。
3. 后端根据附件关联的退款、充值或审批业务重新检查当前账号权限，成功返回短期私有对象地址。
4. 前端在当前页跳转download_url，避免异步后新开窗口被浏览器拦截；地址过期时用户重新打开稳定落地页即可重新解析。
5. 401按后台统一登录失效流程处理并保留当前附件页；无权与不存在展示统一不可访问状态；对象文件不可用或解析失败展示可重试错误，不展示file_key、media_id或底层存储错误。

交互规则：用户不能选择导出字段；角色权限后来变化不改变已经创建任务的文件列，但打开附件时始终按当前权限重新鉴权；任务失败时展示后端原因，不自动重复创建任务。

完成标准：平台、不同层级代理分别验证最终列和数据行范围；无字段状态、任务刷新恢复、CSV/XLSX下载、附件未登录返回、当前有权、权限后来收回、引用不存在和对象不可用流程完整。后端接口发布后，前端只需按上述固定契约接入，不再等待字段选择或永久对象URL方案。
```

### 后端研发需求

**标题**

```text
[BE][UR#42] 统一导出、角色字段权限与受保护附件解析
```

**描述**

```markdown
目标：复用现有导出任务体系，增加本期场景和角色字段级权限，并为退款/充值业务凭证和企微审批附件提供稳定引用、当前权限复核及短期私有下载地址解析。

预计工时：按本冻结范围重新评估；原4～6小时估算未包含全部新增场景、附件本地化与鉴权解析，不能继续沿用。

接口：GET /api/admin/export-fields；POST /api/admin/export-tasks；GET /api/admin/export-tasks/{id}；GET/PUT /api/admin/roles/{role_id}/export-fields；GET /api/admin/attachments/{attachment_ref}/download-url。

规则：最终字段=当前账号有效角色授权字段并集∩场景代码支持字段；超级管理员拥有全部代码目录字段；前端不传fields，账号获授权字段全部导出；字段授权不能扩大菜单、接口、场景或数据行范围；创建任务时快照字段、表头、查询条件和数据范围；Worker不重读实时角色权限；权限解析失败或普通账号最终字段为空时不创建任务。

场景：扩展device、iot_card、order，并增加agent_wallet_transaction、package、refund、exchange、agent_recharge、expiring_asset。agent_recharge保留支付方式、不导出支付通道。

字段目录：密码、密钥、Token、对象Key、企微media_id等永不允许导出的内容不注册；对已注册字段，角色配置是权威，不再增加主观敏感字段层。发布不迁移普通角色默认授权，停机窗口由业务使用超级管理员完成配置后再恢复服务。

附件规则：退款/充值业务凭证与企微审批附件按字段权限导出稳定前端落地页URL，但字段授权不能突破审批主体可见性；代理可导出业务范围内的退款凭证，不能导出或解析平台内部企微审批附件。每个本地附件使用不可变、不可枚举attachment_ref，私有file_key不出后端。企微附件须先保存到本地私有对象存储；不得把临时media_id或预签名URL写入导出文件。

解析流程：前端携带Bearer Token请求attachment_ref；后端解析其关联业务，在每次访问时重新校验当前业务查看权限、数据范围和附件种类可见性；成功返回短期download_url、expires_at、file_name。无权与不存在返回统一错误；权限后来收回后旧导出链接也不可下载，已知引用的代理也不能解析企微内部审批附件。

完成标准：Count与Fetch条件一致，审批摘要和附件引用批量查询，无N+1；字段/表头/权限快照可恢复且无越权列或越权行；导出文件不含file_key、media_id或预签名URL；前后端按未登录、有权、权限收回、引用不存在、对象不存在和附件未本地化完成联调。
```

## UR#40 套餐设计

### 前端研发需求

**标题**

```text
[FE][UR#40] C端下架套餐续费入口
```

**描述**

```markdown
目标：下架套餐不出现在新购列表，但历史使用资产可在当前套餐旁直接续费。

预计工时：前端1.5～2.5小时。

页面入口：C端资产当前套餐区域、套餐购买流程。

页面结构：
1. 当前套餐旁根据 can_purchase 显示“续费”按钮。
2. purchase_mode=renew_only 时只从当前套餐入口进入，不在套餐商城列表展示。
3. 不可续费时按钮禁用或隐藏，并可展示 disabled_reason。
4. 点击续费复用现有购买套餐流程，不拆出第二个套餐列表。

接口约定：GET /api/c/v1/asset/packages 返回 package_id、status、status_name、can_purchase、purchase_mode、disabled_reason；POST /api/c/v1/orders/create 沿用资产和套餐入参。

交互规则：前端不根据套餐上下架状态自行判断资格，以接口字段为准。

完成标准：正常在售购买、历史下架续费、禁用套餐和无历史资格四类场景正确。
```

### 后端研发需求

**标题**

```text
[BE][UR#40] 下架套餐历史用户续费资格校验
```

**描述**

```markdown
目标：统一套餐可售策略，支持资产所有人续费历史使用过的下架套餐。

预计工时：后端2～3小时。

接口：GET /api/c/v1/asset/packages 返回 can_purchase、purchase_mode、disabled_reason；POST /api/c/v1/orders/create 强校验。

规则：禁用套餐始终不可购买；下架套餐只允许当前资产所有人基于有效历史使用记录续费；禁止代理代购；新购列表不返回下架套餐。

完成标准：批量订购和普通下单复用同一可售策略，不能通过直接请求绕过资格校验。
```

## UR#38 不同渠道额度处理

### 前端研发需求

**标题**

```text
[FE][UR#38] 角色默认信用与店铺实际额度管理
```

**描述**

```markdown
目标：角色只配置未来新建店铺的默认信用，已有店铺在资金页单独修改实际额度。

预计工时：前端2.5～3.5小时。

页面入口：客户角色配置页、店铺资金概况页、店铺创建页。

页面结构：
1. 客户角色增加“新建代理默认信用”开关和额度输入，并提示“修改后不会影响已有店铺”。
2. 店铺资金页展示现金余额、冻结金额、实际信用额度、可用金额、欠款金额和版本。
3. 店铺实际额度使用独立调整弹框，展示修改前后金额预览。
4. 平台员工角色不展示信用配置。
5. 代理账号即使能查看自己或下级代理资金，也不展示实际额度修改入口；平台账号只有取得独立信用额度管理权限后才展示。

接口约定：
- PUT /api/admin/roles/{id}/default-credit，body={credit_enabled:bool,credit_limit:int64}。
- PUT /api/admin/shops/{id}/credit-limit，body={credit_enabled:bool,credit_limit:int64,version:int64}。
- GET /api/admin/shops/fund-summary 返回 balance、frozen_balance、credit_enabled、credit_limit、available_balance、is_in_debt、debt_amount、version。

交互规则：金额不在前端重新计算；并发冲突时刷新最新资金概况；关闭信用时额度输入归零；不设置产品层固定额度上限，只执行分/元精确转换和接口整数安全范围校验。欠款只按接口is_in_debt/debt_amount展示，冻结金额不由前端换算为欠款。

完成标准：角色默认、创建店铺初始化、已有店铺调额、代理禁止调额、平台有/无独立权限、降低额度失败和并发冲突提示完整。
```

### 后端研发需求

**标题**

```text
[BE][UR#38] 代理主钱包信用额度与资金不变量
```

**描述**

```markdown
目标：信用额度只属于代理主钱包，角色配置只作为新店铺初始化模板。

预计工时：后端4～5小时。

接口：PUT /api/admin/roles/{id}/default-credit；PUT /api/admin/shops/{id}/credit-limit；GET /api/admin/shops/fund-summary；创建店铺时读取默认角色模板。

不变量：available=balance-frozen_balance+effective_credit且必须>=0；关闭信用时额度为0；存在欠款或冻结导致新可用金额<0时禁止降额或关闭。

规则：修改角色不更新已有店铺；店铺后续角色变化不影响钱包；余额、冻结、信用、版本和资金流水在同一事务维护；调额按version乐观锁更新。

权限：代理账号不得调整自己或任何下级代理额度，不能复用CanManageShop或普通店铺管理权限推导调额权；只有超级管理员或具备独立信用额度管理权限的平台账号可以修改实际额度。角色默认模板只允许超级管理员或具备相应角色管理权限的平台账号配置。信用额度不设产品层固定上限，但必须在int64范围内并拒绝负数与算术溢出。

架构：钱包资金规则迁入Wallet Domain，查询走资金Query。

完成标准：扣款、冻结、解冻、充值、退款回充和调额都维护同一不变量并写资金审计；代理调额请求始终拒绝；额度变更写Audit Event但不伪造金额为0的钱包流水。
```

## UR#37 审核流转

### 前端研发需求

**标题**

```text
[FE][UR#37] 平台企微绑定、代理固定代提交与审批只读详情
```

**描述**

```markdown
目标：平台/超级管理员绑定本人企微发起审批，代理使用固定企微账号代提交；本系统负责配置、状态查看和异常恢复，页面展示的申请人始终是本系统真实业务提交人。

预计工时：前端6～8.5小时，包含平台账号扫码绑定、代理固定代提交状态和多人审批业务映射展示。

页面入口：/system/wecom、平台用户个人中心、/operations/wecom-approvals、退款和线下充值详情。

页面结构：
1. 企微配置页：连接状态、代理固定代提交账号就绪状态与成员显示名、审批场景状态、模板版本列表、模板读取和业务字段到控件的可视化映射发布；不提供固定userid在线修改入口。
2. 平台用户个人中心：绑定状态、成员名称、扫码绑定、重新绑定、解绑；代理账号不展示绑定入口。
3. 审批运行页：业务类型、业务单号、sp_no、状态、模板版本、真实业务提交人、企微发起身份来源、更新时间和异常标识；平台详情抽屉展示审批人、意见、附件、时间线和业务处理结果。
4. 业务详情复用统一approval区块，只读展示，不提供通过、驳回、退回按钮；代理视图只展示真实业务提交人、审批状态、状态时间和业务处理结果，不展示平台内部审批人、意见或审批附件。

接口约定：
- GET /api/admin/wecom/status。
- PUT /api/admin/wecom/approval-scenes/{scene_code}/status。
- POST /api/admin/wecom/approval-templates/inspect、POST /api/admin/wecom/approval-templates/publish、GET /api/admin/wecom/approval-templates。
- POST /api/admin/wecom/account-binding/sessions，返回session_id、login_url、expires_at；GET /api/admin/wecom/account-binding/sessions/{session_id}查询结果；GET/DELETE /api/admin/wecom/account-binding/me。
- GET /api/admin/wecom/approvals、GET /api/admin/wecom/approvals/{id}、POST /api/admin/wecom/approvals/{id}/sync。
- POST /api/admin/wecom/approvals/{id}/bind-sp-no，提交sp_no和必填恢复原因，由后端完成全量业务快照核对后绑定。
- POST /api/admin/wecom/approvals/{id}/confirm-not-created-and-resend，提交必填恢复原因，仅用于人工确认企微未创建后重新发送同一审批申请。

交互规则：平台/超级管理员未绑定时原地提供绑定入口，绑定成功后继续当前表单；代理不要求绑定，固定代提交账号不可用时按后端错误保留表单。审批列表和详情的“申请人”展示真实业务提交人，并可只读标识企微发起身份来源；立即同步只拉取企微详情；通过后撤销且业务已执行时显示高风险提示。

权限约定：/system/wecom、场景/模板维护、账号绑定列表和强制解绑仅超级管理员可见；平台账号只能管理本人绑定，具备独立“企微审批运营”权限后才显示审批运行页和立即同步；“企微审批运营”不包含模板配置、绑定管理或异常恢复。代理不展示企微配置、绑定和运行页，只在其业务数据范围内的退款详情查看审批区块。

信息可见性：代理自己提交的退款资料和业务凭证仍按退款查看权限展示，但企微审批人、内部意见及审批人上传的附件仅平台/超级管理员按退款查看权限访问。详情接口、受保护附件下载和导出执行同一主体权限投影，不能通过attachment_ref或历史导出链接绕过当前权限。

完成标准：配置、平台绑定、代理固定身份状态、列表、详情、同步和异常状态均有加载、空、失败及权限状态。
```

### 后端研发需求

**标题**

```text
[BE][UR#37] 企业微信审批模板、平台绑定、代理代提交、回调与补偿
```

**描述**

```markdown
目标：以稳定业务场景码接入企微审批，替代本地审批流。

预计工时：后端9～11.5小时，包含平台账号扫码绑定、代理固定代提交和多人审批场景映射。

接口：实现企微状态、场景暂停恢复、模板读取发布、平台账号扫码绑定与绑定管理、审批列表详情、立即同步及企微回调接口。

规则：
1. 场景码固定为 refund_approval、offline_recharge_approval，模板ID和控件ID按不可变版本映射。
2. 模板编辑前暂停场景，发布新映射后恢复；历史实例保留模板和提交快照。
3. applyevent发起身份按账号类型分流：平台/超级管理员必须使用当前账号扫码绑定的本人userid；代理使用部署配置中的固定企微userid。真实业务提交人以本地账号和显示快照独立保存，并写入模板必填submitter字段；审批实例保存实际userid与self_binding/agent_proxy来源，列表、详情、通知、权限和审计均以真实业务提交人为准。
4. 回调只验签解密并触发统一SyncApprovalStatus；getapprovaldetail为状态权威来源；审批中实例每2分钟兜底轮询。
5. 首次终态同事务写业务Outbox，business_processed_at保证只执行一次。
6. applyevent已发出但结果未知时禁止自动重试；超级管理员或具备独立异常恢复权限的平台账号可选择“校验并绑定已有sp_no”或“确认未创建后重新发送”。重新发送属于同一审批申请的技术尝试，不创建业务审批轮次；绑定前必须核对企业、模板、实例中的实际企微userid及来源、业务场景、真实业务提交人字段和业务快照，两种动作均保留原尝试并写高风险审计。
7. 场景暂停或模板失效时，新退款/线下充值在任何业务单、审批实例和Outbox落库前直接拒绝；前端保留表单，恢复后由用户重新提交。暂停前已经创建的审批继续回调、轮询同步和处理终态，不受暂停影响。
8. 权限必须拆分：场景暂停恢复、模板读取发布、绑定列表和强制解绑仅超级管理员；平台账号只能管理本人绑定；审批运行列表/详情/立即同步要求独立“企微审批运营”权限；提交未知恢复要求独立“企微审批异常恢复”权限；代理无公共企微管理接口权限，只能按现有业务数据范围查看退款详情中的审批摘要。
9. 审批详情按主体投影：代理只能读取真实业务提交人、审批状态/时间、业务处理结果及其业务范围内的退款资料和业务凭证；审批人、内部意见和审批人上传附件仅平台/超级管理员按业务查看权限读取。附件解析和导出必须复用当前主体权限，禁止旁路访问。

架构：使用wecomapproval、wecomidentity Domain/Application，外部API和加解密进入WeCom Adapter，列表详情走Query。

完成标准：不注册本地审批动作接口，提交未知、模板变更、回调重复和轮询重复均可恢复且可审计。
```

## UR#36 批量订购套餐

### 前端研发需求

**标题**

```text
[FE][UR#36] 批量订购上传支付进度与失败明细
```

**描述**

```markdown
目标：运营按一种支付方式批量导入套餐订单；同一CSV可包含不同代理的资产，系统逐行解析结算代理并展示结果。

预计工时：前端3～4小时。

页面入口：批量订购套餐页或现有订单页批量入口。

入口：页面是否展示沿用前端现有可见性规则；后端不新增批量订购权限码或账号类型拦截，调用复用现有后台认证。

页面结构：
1. 选择一个套餐和整批支付方式（线下或代理钱包）并上传CSV；不选择代理，线下支付时上传整批凭证，不接受Excel。
2. CSV模板下载使用前端静态文件，编码为UTF-8并允许BOM，唯一表头为“资产标识”。
3. 创建后展示任务号、状态、总数、成功数、失败数、金额汇总和失败明细表。
4. 失败明细包含行号、原始/规范资产标识和错误原因；支持按任务ID恢复页面。资产类型由统一资产解析能力识别，当前支持ICCID、卡virtual_no、MSISDN、设备virtual_no、IMEI和SN，前端不要求用户填写资产类型。

接口约定：
- CSV先调用POST /api/admin/storage/upload-url，purpose=bulk_purchase，使用返回的upload_url直传后取得file_key；线下凭证按附件用途直传取得voucher_keys。
- POST /api/admin/bulk-purchases只接收JSON：request_id、单个package_id、payment_method、file_key、voucher_keys；不接收shop_id、multipart或文件字节。
- GET /api/admin/bulk-purchases/{task_id} 返回任务汇总。
- GET /api/admin/bulk-purchases/{task_id}/items?page=&page_size=&status= 返回逐行结果。

交互规则：一个批次固定一个套餐且不能混合支付方式；同一CSV允许不同代理资产，代理归属由后端逐行解析，前端不提交或猜测；任务状态统一为1待处理、2处理中、3已完成、4已失败、5已取消，部分成功只由成功数/失败数表达；wallet批次严格按CSV行号逐行结算，行序就是同一代理余额不足时的订购优先级，当前行余额不足只失败该行并继续尝试后续行，不预占或回滚该代理全部行。

文件级错误异步展示：创建接口通过后不代表CSV内容有效；Worker发现编码、表头、未知列、CSV语法、空文件或超过1000行时，任务整体失败且不会创建任何订单。资产、套餐、归属、钱包和重复行错误才展示为逐行失败。MSISDN未命中或命中多张卡时只失败该行，前端展示后端原因。

完成标准：上传、进度恢复、部分成功、失败筛选和凭证展示完整。
```

### 后端研发需求

**标题**

```text
[BE][UR#36] 批量订购任务与逐行幂等下单
```

**描述**

```markdown
目标：以异步任务逐行创建订单，允许部分成功且每行可审计。

预计工时：后端4～6小时。

接口：POST /api/admin/bulk-purchases；GET /api/admin/bulk-purchases/{task_id}；GET /api/admin/bulk-purchases/{task_id}/items。

入口与规则：后端不新增批量订购权限码、账号类型拦截或任务创建人隔离，复用现有后台认证；创建任务选择单个package_id和整批offline|wallet，wallet表示逐行扣结算代理主钱包，不新增agent_wallet；不接收shop_id；同一CSV可以包含不同代理资产，逐行以资产当前归属解析结算代理；CSV只有“资产标识”一列，资产类型和ID由系统统一资产解析能力识别，当前支持ICCID、卡virtual_no、MSISDN、设备virtual_no、IMEI和SN，批量模块不另写识别规则；CSV和凭证先直传私有对象存储，业务接口只接收稳定file_key/voucher_keys；创建接口校验套餐存在以及对象、上传归属、类型和10MB大小，Worker校验UTF-8（允许BOM）、单列表头、未知列、CSV语法、空文件和1000行上限，文件级错误使任务失败且不创建订单；不接受Excel；标识未命中或无法唯一解析只失败该行；同一文件按解析后的“资产类型+资产ID”判重，同一资产使用不同标识仍只处理首行，后续失败并指出首行号；request_id唯一返回原任务；行幂等键为bulk_purchase:{task_id}:{row_no}。任务统一状态为1待处理、2处理中、3已完成、4已失败、5已取消，部分成功只由success_count/fail_count表达；逐行明细状态为1待处理、2处理中、3成功、4失败。

钱包行事务：严格按CSV行号逐行处理并锁该行资产所属代理的主钱包，按信用不变量校验，订单、扣款、流水、结算代理快照和明细成功状态同事务；不预占整批或某一代理全部行金额，无代理归属、无有效主钱包或余额不足只失败当前行并继续后续行，后续较小金额若余额足够仍可成功；任务统计从明细重新聚合。线下凭证只做本批资料，不校验跨批唯一。

完成标准：Worker处理租约、重复消费、进程中断恢复和部分成功均不产生重复订单或重复扣款。

测试环境约定：已部署测试环境使用Redis DB 6；本地开发和Agent自动化测试强制使用DB 7，测试启动时必须校验实际生效DB并在不是7时失败，禁止向DB 6投递任务，也禁止对DB 7执行FLUSHDB。自动化测试直连当前真实S3并按唯一Key精确清理，不做内存替身；PostgreSQL沿用现有测试库，夹具按唯一运行标识和实际记录ID精确清理，禁止TRUNCATE、清表、模糊删除或修改既有业务数据。Go HTTP集成测试使用Fiber app.Test穿过真实认证和业务链路，捕获任务后直接调用公开Worker Handler，不通过sleep等待后台Worker；实现时沉淀可复用的测试规范、环境守卫/清理Harness、CSV testdata和完整示例，并提供只用于部署冒烟的curl模板。
```

## UR#35 退款审核

### 前端研发需求

**标题**

```text
[FE][UR#35] 退款企微审批详情与业务处理状态
```

**描述**

```markdown
目标：退款创建时提交业务资料，审批在企微完成，本系统只读展示审批及退款处理结果。

预计工时：前端2.5～3.5小时。

页面入口：退款创建、退款列表、退款详情。

页面结构：
1. 创建表单包含订单、退款金额、必填原因、可选备注和1～5个附件；附件提交file_key、file_name、file_size，金额提交后企微审批不可修改；前端不提交实收金额或套餐使用记录。
2. 详情分为退款业务信息、企微审批信息、业务处理结果三个区域。
3. 审批区按主体权限展示：代理只见真实申请人、审批状态和业务处理结果；平台/超级管理员具备退款查看权限时才展示sp_no、审批人、意见、审批附件和时间线。
4. 处理区展示processing_status、失败摘要和“系统重试中/联系管理员”。
5. 不显示本地通过、驳回、退回或人工退款确认按钮。

接口约定：
- POST /api/admin/refunds 创建退款，请求只包含order_id、requested_refund_amount、refund_reason、remark和attachments。
- GET /api/admin/refunds/{id} 返回退款数据、approval对象和processing_status。
- attachments使用现有对象存储上传结果，提交结构为 {file_key,file_name,file_size}[]。
- approval结构至少包含 source、sp_no、status、status_name、template_version、applicant、approvers、comments、attachments、timeline、business_process_result。

交互规则：非代理钱包由财务在系统外人工退款后再在企微通过。企微拒绝后当前退款单终结，详情只读且不提供编辑或重提；业务人员处理拒绝原因后仍需退款时，重新进入创建退款流程并填写金额、凭证和原因，成功后展示新的退款ID、退款单号和审批信息。

完成标准：审批中、通过处理中、处理成功、处理失败、驳回、撤销和通过后撤销异常状态均展示明确；申请金额小于实收金额时明确提示通过后仍按整单终结。
```

### 后端研发需求

**标题**

```text
[BE][UR#35] 退款企微终态与整单退款终结
```

**描述**

```markdown
目标：退款通过企微审批驱动整单业务终态，系统只自动回溯代理主钱包支付。

预计工时：后端4～5小时。

接口：POST /api/admin/refunds；GET /api/admin/refunds；GET /api/admin/refunds/{id}；下线原approve/reject/return/resubmit及任何manual-complete路由。

规则：
1. 创建请求只接受order_id、requested_refund_amount、必填refund_reason、可选remark和1～5个结构化attachments；后端读取订单实收金额并校验0<申请金额<=实收金额，不接受actual_received_amount或package_usage_id。
2. 申请金额在企微只读，审批人只能同意或拒绝。无论申请金额是否等于实收金额，通过后都把订单标记已退款、该订单全部有效套餐失效、全部佣金失效，并禁止再退剩余差额。
3. 非代理主钱包支付由财务系统外退款，企微通过代表人工退款已确认，不调用渠道退款API、不回充个人资产钱包，也不再二次人工确认；actual_refund_amount在资金已完成时写申请金额。
4. 代理钱包订单通过后只按原扣款流水幂等回溯原代理主钱包并写唯一退款流水；缺少原流水则失败，不按当前关系猜测钱包。
5. 已发放佣金全额从佣金钱包扣回并允许负余额，其他未发放佣金直接失效；佣金记录保存结构化失效原因、退款引用和失效时间。订单套餐按整单失效，主套餐级联加油包并尝试下一排队主套餐。
6. 驳回更新为已拒绝；撤销/删除更新为已撤销；通过后撤销且资金已执行不自动冲正，记录critical审计和站内告警。
7. 一张退款单只创建一条企微审批申请，业务表保存唯一approval_instance_id并由(biz_type,biz_id)唯一约束防重。正常结果只有同意或拒绝，任一结果产生后审批与退款单同时完结；拒绝后原退款单不可修改、不可重提。若仍需退款，必须重新调用创建接口，生成新的退款ID、退款单号、业务快照、提交人快照和企微审批；旧单只保留为历史事实，已拒绝退款不阻止新建，但仍需阻止存在其他活跃退款时重复创建。撤销、删除或通过后撤销只作外部异常处置，不作为自动放行新退款的依据。
8. 代理按既有店铺层级和退款业务权限查看本店及可管理下级退款，不再按creator隔离；代理不见审批人、内部意见或审批人附件，平台/超级管理员也须有退款业务查看权限。
9. 企微终态通过Outbox和可靠Worker处理，processing_status固定0未触发、1处理中、2处理成功、3处理失败，局部失败可安全重试，不使用进程内Goroutine。

完成标准：审批状态与业务处理状态分离，重复终态不重复回款/扣佣/失效套餐，失败任务可可靠重试；实现期必须通过可编程Adapter自动化和真实企微两张独立退款验收（代理代提交同意、平台本人提交拒绝），INT-06不能替代。
```

## UR#34 充值审核流程

### 前端研发需求

**标题**

```text
[FE][UR#34] 代理扫码充值与员工线下充值审批页面
```

**描述**

```markdown
目标：区分代理在线扫码充值和平台员工线下代充值，两条路径不混用。

预计工时：前端5～7小时，包含在线扫码充值和线下审批两条页面链路。

页面入口：代理资金充值页、后台线下代充值创建页、充值列表和详情。

页面结构：
1. 在线充值：金额输入最低100元、支付方式选择、二维码、支付状态和钱包入账状态；不显示审批区域，也不展示本地推算的精确过期倒计时。
2. 线下代充值：选择店铺、金额、备注、附件；提交后显示企微审批和入账处理状态。
3. 充值详情按approval_source显示：none隐藏审批区，wecom显示只读企微详情。
4. 不显示本地确认入账、驳回按钮和操作密码输入框。

接口约定：
- GET /api/admin/agent-recharges/payment-methods 返回真正可用的 methods:string[]、min_amount:int64、max_amount:int64，不暴露支付通道或配置。
- POST /api/admin/agent-recharges，在线入参 amount、payment_method、request_id；线下入参 shop_id、amount、payment_method=offline、remark、attachments、request_id。
- 在线返回 recharge_id、recharge_no、qr_content、payment_status、processing_status、approval_source=none，不返回 expires_at。
- GET /api/admin/agent-recharges/{id}/payment-status 只读取本地状态，返回 payment_status、payment_status_name、processing_status、processing_status_name。
- GET /api/admin/agent-recharges/{id} 返回充值详情、approval和processing_status。
- 线下attachments使用现有对象存储上传结果，结构为 {file_key,file_name,file_size}[]。

交互规则：在线状态每3秒轮询本地状态，页面不可见暂停；每次用户主动创建支付都使用新的request_id创建全新充值单和支付单，旧单等待回调或后端查单自然收敛；线下提交失败保留表单。

完成标准：微信、支付宝、第三方关闭/迟到成功、重复回调后的最终状态、支付成功但入账失败补偿、线下审批通过入账和驳回状态均可展示；在线和线下实际到账后均发送代理站内到账通知。
```

### 后端研发需求

**标题**

```text
[BE][UR#34] 代理在线充值入账与线下充值企微终态
```

**描述**

```markdown
目标：实现无需审批的代理在线充值，以及需要企微审批的平台员工线下代充值。

预计工时：后端8～11小时，包含支付渠道接入和线下审批入账。

接口：GET /api/admin/agent-recharges/payment-methods；POST /api/admin/agent-recharges；GET /api/admin/agent-recharges/{id}/payment-status；GET /api/admin/agent-recharges/{id}；下线offline-pay和reject旧接口。

在线规则：代理只充当前店铺且不提交shop_id，最低10000分；支持微信Native和支付宝PreCreate；每次主动创建都是全新充值单和支付单；统一返回qr_content且不返回expires_at。支付回调和受控查单进入同一幂等确认用例并校验金额、配置、交易号和业务单；先固化支付成功与入账Outbox，再由可靠Worker独立事务更新主钱包、版本、唯一流水、充值完成状态和审计。重复回调或任务不重复入账，迟到成功不能吞掉已付资金。

线下规则：仅平台/超管创建，金额大于0，目标店铺和1～5个结构化付款凭证必填，金额提交后固定；创建后提交企微，审批只能同意或拒绝。通过后自动增加代理主钱包并写流水，无操作密码；recharge:{recharge_no}防重；驳回终结原单且不支持退回/重提，撤销/删除为已关闭；通过后撤销且已入账不自动扣回。

完成标准：两条路径和权限严格隔离，支付/审批/钱包处理状态独立，支付成功但入账失败可补偿，支付查单与企微终态重复同步不重复加钱；钱包到账后向目标代理发送防重站内通知。本地支付网络使用可控Adapter，真实微信/支付宝在测试环境手工验收，真实企微线下充值为实现门禁。
```

## UR#33 套餐临期提醒

### 前端研发需求

**标题**

```text
[FE][UR#33] 临期列表高亮置顶通知与续费入口
```

**描述**

```markdown
目标：统一展示资产预计最终到期的临期状态，并提供站内通知和续费入口。

预计工时：前端3～4.5小时，不含公共站内通知中心工时。

页面入口：/operations/expiring-assets或现有临期页、卡/设备列表和详情、代理首页、C端资产页、通知中心。

页面结构：
1. 临期独立列表展示资产、店铺、当前套餐、预计最终到期、剩余天数和颜色；0-3天固定置顶，再按到期时间升序。
2. 普通资产列表只按颜色高亮，不改变原排序。
3. 代理首页展示临期卡数量和设备数量。
4. C端资产页展示临期状态和续费按钮。
5. 通知中心展示15天、7天、3天站内提醒，不展示企微临期消息。

接口约定：
- GET /api/admin/expiring-assets 支持 asset_type、keyword、shop_id、package_id、days_min、days_max、expires_from、expires_to、page、size。
- items返回 asset_type、asset_id、identifier、shop_name、package_name、estimated_final_expires_at、days_until_final_expiry、expiry_level、expiry_level_name、can_renew。
- 资产列表/详情和GET /api/c/v1/asset/info返回同一临期字段。
- 通知复用通知接口。

交互规则：颜色为8-15天粉红、4-7天紫色、0-3天红色；已过期和不可预计资产不进入临期页。

完成标准：列表排序、普通列表高亮、首页计数、C端续费和通知跳转使用同一到期结果。
```

### 后端研发需求

**标题**

```text
[BE][UR#33] 最终到期临期Query与15/7/3站内通知
```

**描述**

```markdown
目标：基于统一预计最终到期Query提供临期查询和站内通知。

预计工时：后端4～6小时，不含公共站内通知基础设施工时。

接口：GET /api/admin/expiring-assets；扩展卡/设备列表详情、代理首页和GET /api/c/v1/asset/info；复用通知接口和scene=expiring_asset导出。

规则：按Asia/Shanghai自然日计算0-15天；已过期和不可预计资产不计入；临期页0-3天优先，再按最终到期升序；普通列表不改排序。

通知：每日任务按package_usage_id+recipient+channel+node防重，节点为15/7/3天；漏跑只补当前最近未发送节点；接收店铺主账号和业务员；只发站内通知。

完成标准：查询、首页计数、C端和通知共用同一最终到期算法，重复任务不重复通知。
```

## 技术用户需求 七月迭代公共开发基础

> 建议与全局审计、站内通知一起挂到“七月迭代公共基础设施”技术用户需求下。

### 前端研发需求

**标题**

```text
[FE][TECH] 七月迭代公共状态与异步任务交互
```

**描述**

```markdown
目标：先统一现有导出任务接口与批量任务页面的加载、错误和异步任务交互；系统配置和 Outbox 运维页面不在本研发需求范围。

预计工时：前端1～2小时。

交付内容：
1. 统一加载、空数据、权限不足、接口失败和重试状态。
2. `GET /api/admin/export-tasks` 兼容新增或统一 `task_id`、`total_count`、`success_count`、`failed_count`、`error_code`、`error_summary`、`updated_at`，原字段不删除、不改名。
3. `GET /api/admin/export-tasks/{id}` 同步新增或统一上述字段，字段语义与列表一致。
4. 统一异步任务进度结构：状态固定为1待处理、2处理中、3已完成、4已失败、5已取消；部分成功仍为已完成，只通过总数、成功数和失败数表达。
5. 创建任务后保存 `task_id`；刷新或重新进入页面查询原任务，不得重新创建。
6. 按2秒、3秒、5秒递增轮询，最大间隔10秒；终态停止，页面不可见暂停，恢复后立即刷新。
7. 403显示无权限且不重试；瞬时失败保留已有数据和输入并提供重试；用户错误文案展示安全的 `error_summary`。

不包含：`GET /api/admin/system-configs`、`PUT /api/admin/system-configs/{key}` 的新页面，以及 Outbox 监控/人工恢复页面。支付配置页面继续归 UR#48，待正式配置 Key 和审计 Adapter 就绪后联调。

完成标准：导出页面先完成上述兼容字段和交互规则；设备批量分配、批量订购在对应业务接口落地后复用同一状态语义。
```

### 后端研发需求

**标题**

```text
[BE][TECH] 七月迭代公共迁移幂等与异步任务基础
```

**描述**

```markdown
目标：补齐本期跨需求共用的数据迁移、Outbox、幂等和异步任务能力。

预计工时：后端4～5小时。

交付内容：
1. 按标准稿准备增量迁移、索引、约束和停机迁移检查。
2. 统一Outbox写入和消费状态，供企微终态、钱包通知和状态同步使用。
3. 统一request_id防重、状态条件更新、乐观锁和Worker处理租约。
4. 统一异步任务状态及失败明细Query，Asynq载荷只传结构化数据。
5. 为渐进DDD新增的Domain、Application、Query和Adapter提供项目内一致目录及装配方式。

完成标准：业务研发需求复用公共能力，不分别创建不兼容的幂等、Outbox和任务状态实现。
```

## 技术用户需求 公共站内通知

### 前端研发需求

**标题**

```text
[FE][TECH] 顶部通知铃铛与站内通知中心
```

**描述**

```markdown
目标：提供本期余额预警、临期提醒、审批结果和系统告警共用的站内通知界面。

预计工时：前端3～4小时。

页面入口：顶部全局导航、/notifications。

页面结构：
1. 顶部铃铛固定宽度显示0、1～99或99+，点击展示最近10条通知抽屉。
2. 抽屉按全部、审批、临期、同步/系统分类，并提供进入通知中心入口。
3. 通知中心支持分类、类型、严重级别、已读状态筛选及全部已读。
4. 点击通知先标记已读，再根据ref_type受控跳转；未知目标只展示正文。

接口约定：GET /api/admin/notifications/unread-count、unread-summary、notifications；PUT /api/admin/notifications/{id}/read、read-all；GET /api/admin/notifications/{id}/target。C端使用对应/api/c/v1/notifications接口。

完成标准：余额、临期、审批和系统通知展示一致，未读数和列表状态同步，无任意URL跳转。
```

### 后端研发需求

**标题**

```text
[BE][TECH] 站内通知基础设施与受控跳转
```

**描述**

```markdown
目标：为本期所有通知场景提供统一存储、模板、接收人、防重、未读和受控跳转能力。

预计工时：后端3～4小时。

接口：实现管理端和C端未读数、分类汇总、分页列表、单条已读、全部已读及受控目标解析接口。

规则：
1. 通知使用稳定业务键防重，按场景解析店铺主账号、业务员、申请人等接收人。
2. target只返回受控ref_type和ref_id，不保存或返回任意URL。
3. 通知失败不回滚资金、审批或套餐业务事务，由Outbox可靠重试。
4. 余额预警、15/7/3临期、审批结果和系统告警复用统一模板注册。

完成标准：重复事件不重复通知，接收人停用时跳过，管理端和C端数据范围正确。
```

## 技术用户需求 全局多视角审计与外部集成追踪

> 当前禅道CSV没有对应父用户需求。先创建该技术用户需求，再创建以下FE、BE研发需求。

### 前端研发需求

**标题**

```text
[FE][TECH] 全局多视角审计中心
```

**描述**

```markdown
目标：提供一个工作台式审计中心，从全局、人员、资源、链路、资金、风险和外部集成多个视角追踪系统操作。

预计工时：前端6～8小时。

页面入口：/operations/audit。

页面结构：
1. Tab：全局事件、人员行为、资源轨迹、请求/业务链路、资金审计、风险事件、外部集成。
2. 公共筛选：时间、操作编码、结果、风险级别、操作者、资源、request_id、correlation_id。
3. 列表展示时间、操作者、操作、主要资源、结果、风险和链路编号；详情抽屉展示脱敏前后数据、关联资源和上下游事件。
4. 资源轨迹先搜索候选资源再打开时间线；外部集成按provider、operation、触发来源和序列展示立即/3分钟/5分钟结果。
5. 敏感字段默认脱敏；查看敏感值和导出使用独立权限。

接口约定：GET /api/admin/audit/events及详情、actors、resources/search及timeline、requests和correlations timeline、risks、integrations、finance/timeline；POST /api/admin/audit/exports。

完成标准：每个视角有独立筛选和空状态，可通过request_id/correlation_id在事件间跳转，旧历史日志可只读展示。
```

### 后端研发需求

**标题**

```text
[BE][TECH] Audit Event与Integration Log统一审计
```

**描述**

```markdown
目标：一次停机发布切换全局审计写入，并提供多视角Query。

预计工时：后端8～11小时。

数据：tb_audit_event、tb_audit_event_resource、tb_integration_log；Audit Event不可变，支持主资源、影响资源和引用资源。

接口：实现事件、人员、资源、request、correlation、风险、外部集成、资金和导出Query。

规则：资金、权限、审批和关键配置变更与业务事务同事务写审计；失败和拒绝在回滚后短事务记录；外部交互写Integration Log；密码、Token、Secret、私钥、验证码、完整证件、签名URL和media_id禁止入库。

迁移：新旧敏感写操作统一接入Audit Writer，旧日志停止新写入；历史数据通过Query UNION ALL只读投影，不双写。

完成标准：多资源关联、链路追踪、脱敏、保留周期和审计自身权限完整，关键审计失败能阻止对应业务提交。
```

## 联调研发需求

> 建议先建立技术用户需求“7月迭代跨模块联调与发布验收”，以下每条作为可独立指派的联调研发需求。问题修复仍回到对应FE/BE研发需求。

### INT-01 资产实名、复机与状态同步联调

**标题**

```text
[INT-01] 资产实名复机与状态同步联调
```

**描述**

```markdown
关联需求：UR#94、UR#73、UR#62、UR#53。

参与工时参考：前端1～1.5小时、后端1～1.5小时，从关联FE/BE研发需求工时中拆出，不新增总工时。

进入条件：H5流程、实名策略接口、卡状态统一应用用例、轮询和0/3/5任务已完成。

联调范围：
1. 不同realname_link_type下的实名要求和行业卡复机结果。
2. none、before_order、after_order三种H5流程。
3. 查询、获取实名链接、停复机、支付、套餐激活等埋点后的立即/3分钟/5分钟轨迹。
4. 19位和20位ICCID实名回调路由。
5. 卡和设备实名筛选及设备快照更新。

完成标准：前端状态、业务数据、审计轨迹和上游调用结果一致，无旧逻辑直接改卡状态。
```

### INT-02 换货完整链路联调

**标题**

```text
[INT-02] 换货完整链路联调
```

**描述**

```markdown
关联需求：UR#98、UR#86、UR#57、UR#45。

参与工时参考：前端0.5～1小时、后端0.5～1小时，从关联FE/BE研发需求工时中拆出，不新增总工时。

进入条件：换货创建/完成接口、退款拦截、列表搜索和资产详情换货链已完成。

联调范围：退款中拦截、平台库存新资产继承旧店铺、其他店铺新资产拒绝、完成换货、旧店铺历史可见、新旧资产独立搜索、前代后代跳转和无权限显示。

完成标准：换货事务数据一致，列表、详情、资产归属和审计结果一致。
```

### INT-03 套餐生命周期联调

**标题**

```text
[INT-03] 套餐授权购买续费到期与临期联调
```

**描述**

```markdown
关联需求：UR#55、UR#46、UR#43、UR#40、UR#33。

参与工时参考：前端1～1.5小时、后端1～1.5小时，从关联FE/BE研发需求工时中拆出，不新增总工时。

进入条件：套餐授权候选、生效条件快照、可售策略、最终到期Query和临期页面已完成。

联调范围：批量授权及已授权置灰、默认/覆盖生效条件、购买快照、下架套餐历史续费、多个排队套餐最终到期、临期高亮/置顶、15/7/3通知和C端续费。

完成标准：后台、C端、临期列表、通知和导出使用同一套餐生命周期结果。
```

### INT-04 CSV批量任务与导出联调

**标题**

```text
[INT-04] CSV批量任务与导出联调
```

**描述**

```markdown
关联需求：UR#49、UR#36、UR#42。

参与工时参考：前端1～1.5小时、后端1～1.5小时，从关联FE/BE研发需求工时中拆出，不新增总工时。

进入条件：前端静态模板、上传页面、异步任务、Worker、失败明细和导出场景完成。

联调范围：表头校验、文件限制、重复request_id、部分成功、失败明细、任务刷新恢复、代理/系列双命令隔离、批量订购钱包扣款、导出字段权限和文件下载。

完成标准：任务中断可恢复，不重复分配、下单或扣款，前端进度与后端统计一致。
```

### INT-05 支付钱包信用与余额预警联调

**标题**

```text
[INT-05] 支付钱包信用充值与余额预警联调
```

**描述**

```markdown
关联需求：UR#48、UR#38、UR#34、UR#36、UR#96、UR#97。

参与工时参考：前端1～1.5小时、后端1～1.5小时，从关联FE/BE研发需求工时中拆出，不新增总工时。

进入条件：支付配置、在线充值、钱包领域、信用调额、业务员关联和低余额通知完成。

联调范围：卡/设备支付方式、微信/支付宝扫码充值、支付回调幂等、角色默认信用、已有店铺调额、批量订购扣款、现金余额跨越100元阈值及店铺主账号/业务员通知。

完成标准：资金不变量成立，支付或审批重复回调不重复入账，信用额度不参与现金余额预警。
```

### INT-06 企业微信审批退款与线下充值联调

**标题**

```text
[INT-06] 企业微信审批退款与线下充值联调
```

**描述**

```markdown
关联需求：UR#37、UR#35、UR#34、UR#44。

参与工时参考：前端1.5～2小时、后端1.5～2小时，从关联FE/BE研发需求工时中拆出，不新增总工时。

进入条件：模板映射、平台账号绑定、代理固定代提交账号验证、审批提交、回调、2分钟轮询、退款和线下充值终态处理完成。

联调范围：平台账号扫码绑定与未绑定拦截、代理固定代提交账号有效/失效拦截、两类企微发起身份、真实业务提交人展示、模板发布、发起审批、意见附件、通过/驳回/撤销/删除、回调重复、立即同步、退款人工处理、代理钱包回溯、线下充值入账和列表审批摘要。

完成标准：本系统无审批按钮，企微状态与业务处理状态分离，终态重复同步不重复执行资金动作。
```

### INT-07 Gateway卡限速联调

**标题**

```text
[INT-07] Gateway卡限速联调
```

**描述**

```markdown
关联需求：UR#47。

参与工时参考：前端0.5～1小时、后端0.5～1小时，从关联FE/BE研发需求工时中拆出，不新增总工时。

进入条件：统一限速接口、卡和设备详情入口、Gateway联调配置完成。

联调范围：单卡固定 `code`、恢复不限速与限到0kbps区分、越权卡、Gateway 明确失败/结果未知及审计记录；确认设备端没有限速入口。

完成标准：Gateway收到的cardNo始终为卡ICCID，设备号不会被发送，上游结果在页面和审计中可追踪。
```

### INT-08 全链路与停机发布验收

**标题**

```text
[INT-08] 7月迭代全链路与停机发布验收
```

**描述**

```markdown
关联需求：全部激活用户需求、七月迭代公共开发基础、全局审计和公共站内通知技术需求。

预计工时：前端3～4小时、后端4～5小时，本项为额外发布工时并计入总工时。

进入条件：INT-01至INT-07完成；公共基础12号票、全局审计19号票、公共站内通知08号票及各业务最终发布门禁完成；迁移脚本、配置、Worker和发布清单已准备。

验收范围：权限与越权、通知跳转、审计多视角、历史数据兼容、旧审批接口下线、旧审计停止写入、异步任务恢复、停机迁移、配置校验和回滚边界；全系统审计覆盖基线无未分类入口，系统配置更新和 Outbox 人工恢复已注入正式 Audit Writer；每个实际投递事件已登记事件类型、载荷版本、消费者、幂等键、业务失败明细和通知策略；告警阈值已填写具体数值与责任人。

完成标准：前端和后端使用冻结接口契约，能从样本回答谁在什么入口、对什么资源、如何操作、前后变化和关联请求/业务链路；旧 Writer 无新增，消费者先于生产者就绪，核心链路人工验收通过。任何审计覆盖空白、正式 Adapter 未装配、事件无消费者或阈值未确定都阻止放量。
```
